aboutsummaryrefslogtreecommitdiffstats
path: root/src/qml/jsruntime
diff options
context:
space:
mode:
Diffstat (limited to 'src/qml/jsruntime')
-rw-r--r--src/qml/jsruntime/qv4argumentsobject.cpp6
-rw-r--r--src/qml/jsruntime/qv4arraydata.cpp269
-rw-r--r--src/qml/jsruntime/qv4arraydata_p.h78
-rw-r--r--src/qml/jsruntime/qv4arrayobject.cpp28
-rw-r--r--src/qml/jsruntime/qv4dateobject.cpp8
-rw-r--r--src/qml/jsruntime/qv4functionobject.cpp14
-rw-r--r--src/qml/jsruntime/qv4lookup.cpp17
-rw-r--r--src/qml/jsruntime/qv4mm.cpp29
-rw-r--r--src/qml/jsruntime/qv4object.cpp43
-rw-r--r--src/qml/jsruntime/qv4object_p.h7
-rw-r--r--src/qml/jsruntime/qv4objectiterator.cpp31
-rw-r--r--src/qml/jsruntime/qv4objectiterator_p.h5
-rw-r--r--src/qml/jsruntime/qv4objectproto.cpp10
-rw-r--r--src/qml/jsruntime/qv4profiling_p.h10
-rw-r--r--src/qml/jsruntime/qv4runtime.cpp6
-rw-r--r--src/qml/jsruntime/qv4script.cpp13
-rw-r--r--src/qml/jsruntime/qv4script_p.h2
17 files changed, 316 insertions, 260 deletions
diff --git a/src/qml/jsruntime/qv4argumentsobject.cpp b/src/qml/jsruntime/qv4argumentsobject.cpp
index 9ac279bf87..4af8927a2e 100644
--- a/src/qml/jsruntime/qv4argumentsobject.cpp
+++ b/src/qml/jsruntime/qv4argumentsobject.cpp
@@ -78,7 +78,7 @@ void ArgumentsObject::fullyCreate()
uint numAccessors = qMin((int)context()->d()->function->formalParameterCount(), context()->d()->realArgumentCount);
uint argCount = qMin(context()->d()->realArgumentCount, context()->d()->callData->argc);
- ArrayData::realloc(this, ArrayData::Sparse, 0, argCount, true);
+ ArrayData::realloc(this, ArrayData::Sparse, argCount, true);
context()->d()->engine->requireArgumentsAccessors(numAccessors);
mappedArguments().ensureIndex(engine(), numAccessors);
for (uint i = 0; i < (uint)numAccessors; ++i) {
@@ -97,7 +97,7 @@ bool ArgumentsObject::defineOwnProperty(ExecutionContext *ctx, uint index, const
fullyCreate();
Scope scope(ctx);
- Property *pd = arrayData()->getProperty(index);
+ Property *pd = arrayData() ? arrayData()->getProperty(index) : 0;
Property map;
PropertyAttributes mapAttrs;
bool isMapped = false;
@@ -106,6 +106,7 @@ bool ArgumentsObject::defineOwnProperty(ExecutionContext *ctx, uint index, const
isMapped = arrayData()->attributes(index).isAccessor() && pd->getter() == context()->d()->engine->argumentsAccessors[index].getter();
if (isMapped) {
+ Q_ASSERT(arrayData());
mapAttrs = arrayData()->attributes(index);
map.copy(*pd, mapAttrs);
setArrayAttributes(index, Attr_Data);
@@ -119,6 +120,7 @@ bool ArgumentsObject::defineOwnProperty(ExecutionContext *ctx, uint index, const
ctx->d()->strictMode = strict;
if (isMapped && attrs.isData()) {
+ Q_ASSERT(arrayData());
ScopedCallData callData(scope, 1);
callData->thisObject = this->asReturnedValue();
callData->args[0] = desc.value;
diff --git a/src/qml/jsruntime/qv4arraydata.cpp b/src/qml/jsruntime/qv4arraydata.cpp
index d58dbb91d4..3235a116ee 100644
--- a/src/qml/jsruntime/qv4arraydata.cpp
+++ b/src/qml/jsruntime/qv4arraydata.cpp
@@ -87,65 +87,60 @@ const ArrayVTable SparseArrayData::static_vtbl =
SparseArrayData::length
};
+Q_STATIC_ASSERT(sizeof(ArrayData::Data) == sizeof(SimpleArrayData::Data));
+Q_STATIC_ASSERT(sizeof(ArrayData::Data) == sizeof(SparseArrayData::Data));
-void ArrayData::realloc(Object *o, Type newType, uint offset, uint alloc, bool enforceAttributes)
+void ArrayData::realloc(Object *o, Type newType, uint requested, bool enforceAttributes)
{
ArrayData *d = o->arrayData();
- uint oldAlloc = 0;
+ uint alloc = 8;
uint toCopy = 0;
- if (alloc < 8)
- alloc = 8;
+ uint offset = 0;
if (d) {
bool hasAttrs = d->attrs();
enforceAttributes |= hasAttrs;
- if (!offset && alloc <= d->alloc() && newType == d->type() && hasAttrs == enforceAttributes)
+ if (requested <= d->alloc() && newType == d->type() && hasAttrs == enforceAttributes)
return;
- oldAlloc = d->alloc();
if (d->type() < Sparse) {
- offset = qMax(offset, static_cast<SimpleArrayData *>(d)->offset());
+ offset = static_cast<SimpleArrayData *>(d)->d()->offset;
toCopy = static_cast<SimpleArrayData *>(d)->len();
} else {
- Q_ASSERT(!offset);
toCopy = d->alloc();
- newType = Sparse;
}
+ if (d->type() > newType)
+ newType = d->type();
}
if (enforceAttributes && newType == Simple)
newType = Complex;
- alloc = qMax(alloc, 2*oldAlloc) + offset;
- size_t size = alloc*sizeof(Value);
+ while (alloc < requested)
+ alloc *= 2;
+ size_t size = sizeof(ArrayData::Data) + (alloc - 1)*sizeof(Value);
if (enforceAttributes)
size += alloc*sizeof(PropertyAttributes);
+ ArrayData *newData;
if (newType < Sparse) {
- size += sizeof(SimpleArrayData::Data);
- SimpleArrayData *newData = static_cast<SimpleArrayData *>(o->engine()->memoryManager->allocManaged(size));
- new (newData->d()) SimpleArrayData::Data(o->engine());
- newData->setAlloc(alloc - offset);
- newData->setType(newType);
- newData->setArrayData(reinterpret_cast<Value *>(newData->d() + 1) + offset);
- newData->setAttrs(enforceAttributes ? reinterpret_cast<PropertyAttributes *>(newData->arrayData() + alloc) + offset : 0);
- newData->offset() = offset;
- newData->len() = d ? static_cast<SimpleArrayData *>(d)->len() : 0;
- o->setArrayData(newData);
+ SimpleArrayData *n = static_cast<SimpleArrayData *>(o->engine()->memoryManager->allocManaged(size));
+ new (n->d()) SimpleArrayData::Data(o->engine());
+ n->d()->offset = 0;
+ n->len() = d ? static_cast<SimpleArrayData *>(d)->len() : 0;
+ newData = n;
} else {
- size += sizeof(SparseArrayData::Data);
- SparseArrayData *newData = static_cast<SparseArrayData *>(o->engine()->memoryManager->allocManaged(size));
- new (newData->d()) SparseArrayData::Data(o->engine());
- newData->setAlloc(alloc);
- newData->setType(newType);
- newData->setArrayData(reinterpret_cast<Value *>(newData->d() + 1));
- newData->setAttrs(enforceAttributes ? reinterpret_cast<PropertyAttributes *>(newData->arrayData() + alloc) : 0);
- o->setArrayData(newData);
+ SparseArrayData *n = static_cast<SparseArrayData *>(o->engine()->memoryManager->allocManaged(size));
+ new (n->d()) SparseArrayData::Data(o->engine());
+ newData = n;
}
+ newData->setAlloc(alloc);
+ newData->setType(newType);
+ newData->setAttrs(enforceAttributes ? reinterpret_cast<PropertyAttributes *>(newData->d()->arrayData + alloc) : 0);
+ o->setArrayData(newData);
if (d) {
- memcpy(o->arrayData()->arrayData(), d->arrayData(), sizeof(Value)*toCopy);
if (enforceAttributes) {
if (d->attrs())
memcpy(o->arrayData()->attrs(), d->attrs(), sizeof(PropertyAttributes)*toCopy);
@@ -153,56 +148,56 @@ void ArrayData::realloc(Object *o, Type newType, uint offset, uint alloc, bool e
for (uint i = 0; i < toCopy; ++i)
o->arrayData()->attrs()[i] = Attr_Data;
}
+
+ if (toCopy > d->d()->alloc - offset) {
+ uint copyFromStart = toCopy - (d->d()->alloc - offset);
+ memcpy(o->arrayData()->d()->arrayData + toCopy - copyFromStart, d->d()->arrayData, sizeof(Value)*copyFromStart);
+ toCopy -= copyFromStart;
+ }
+ memcpy(o->arrayData()->d()->arrayData, d->d()->arrayData + offset, sizeof(Value)*toCopy);
}
if (newType != Sparse)
return;
- SparseArrayData *newData = static_cast<SparseArrayData *>(o->arrayData());
+ SparseArrayData *sparse = static_cast<SparseArrayData *>(o->arrayData());
+
+ uint *lastFree;
if (d && d->type() == Sparse) {
SparseArrayData *old = static_cast<SparseArrayData *>(d);
- newData->setSparse(old->sparse());
+ sparse->setSparse(old->sparse());
old->setSparse(0);
- newData->freeList() = old->freeList();
+ sparse->freeList() = old->freeList();
+ lastFree = &sparse->freeList();
} else {
- newData->setSparse(new SparseArray);
- uint *lastFree = &newData->freeList();
+ sparse->setSparse(new SparseArray);
+ lastFree = &sparse->freeList();
for (uint i = 0; i < toCopy; ++i) {
- if (!newData->arrayData()[i].isEmpty()) {
- SparseArrayNode *n = newData->sparse()->insert(i);
+ if (!sparse->arrayData()[i].isEmpty()) {
+ SparseArrayNode *n = sparse->sparse()->insert(i);
n->value = i;
} else {
*lastFree = i;
- newData->arrayData()[i].tag = Value::Empty_Type;
- lastFree = &newData->arrayData()[i].uint_32;
+ sparse->arrayData()[i].tag = Value::Empty_Type;
+ lastFree = &sparse->arrayData()[i].uint_32;
}
}
}
- uint *lastFree = &newData->freeList();
- for (uint i = toCopy; i < newData->alloc(); ++i) {
- *lastFree = i;
- newData->arrayData()[i].tag = Value::Empty_Type;
- lastFree = &newData->arrayData()[i].uint_32;
+ if (toCopy < sparse->alloc()) {
+ for (uint i = toCopy; i < sparse->alloc(); ++i) {
+ *lastFree = i;
+ sparse->arrayData()[i].tag = Value::Empty_Type;
+ lastFree = &sparse->arrayData()[i].uint_32;
+ }
+ *lastFree = UINT_MAX;
}
- *lastFree = newData->alloc();
-
// ### Could explicitly free the old data
}
-
-void SimpleArrayData::getHeadRoom(Object *o)
-{
- SimpleArrayData *dd = static_cast<SimpleArrayData *>(o->arrayData());
- Q_ASSERT(dd);
- Q_ASSERT(!dd->offset());
- uint offset = qMax(dd->len() >> 2, (uint)16);
- realloc(o, Simple, offset, 0, false);
-}
-
ArrayData *SimpleArrayData::reallocate(Object *o, uint n, bool enforceAttributes)
{
- realloc(o, Simple, 0, n, enforceAttributes);
+ realloc(o, Simple, n, enforceAttributes);
return o->arrayData();
}
@@ -211,7 +206,7 @@ void ArrayData::ensureAttributes(Object *o)
if (o->arrayData() && o->arrayData()->attrs())
return;
- ArrayData::realloc(o, Simple, 0, 0, true);
+ ArrayData::realloc(o, Simple, 0, true);
}
@@ -220,7 +215,7 @@ void SimpleArrayData::markObjects(Managed *d, ExecutionEngine *e)
SimpleArrayData *dd = static_cast<SimpleArrayData *>(d);
uint l = dd->len();
for (uint i = 0; i < l; ++i)
- dd->arrayData()[i].mark(e);
+ dd->data(i).mark(e);
}
ReturnedValue SimpleArrayData::get(const ArrayData *d, uint index)
@@ -228,7 +223,7 @@ ReturnedValue SimpleArrayData::get(const ArrayData *d, uint index)
const SimpleArrayData *dd = static_cast<const SimpleArrayData *>(d);
if (index >= dd->len())
return Primitive::emptyValue().asReturnedValue();
- return dd->arrayData()[index].asReturnedValue();
+ return dd->data(index).asReturnedValue();
}
bool SimpleArrayData::put(Object *o, uint index, ValueRef value)
@@ -236,7 +231,7 @@ bool SimpleArrayData::put(Object *o, uint index, ValueRef value)
SimpleArrayData *dd = static_cast<SimpleArrayData *>(o->arrayData());
Q_ASSERT(index >= dd->len() || !dd->attrs() || !dd->attrs()[index].isAccessor());
// ### honour attributes
- dd->arrayData()[index] = value;
+ dd->data(index) = value;
if (index >= dd->len()) {
if (dd->attrs())
dd->attrs()[index] = Attr_Data;
@@ -252,12 +247,12 @@ bool SimpleArrayData::del(Object *o, uint index)
return true;
if (!dd->attrs() || dd->attrs()[index].isConfigurable()) {
- dd->arrayData()[index] = Primitive::emptyValue();
+ dd->data(index) = Primitive::emptyValue();
if (dd->attrs())
dd->attrs()[index] = Attr_Data;
return true;
}
- if (dd->arrayData()[index].isEmpty())
+ if (dd->data(index).isEmpty())
return true;
return false;
}
@@ -276,20 +271,14 @@ void SimpleArrayData::push_front(Object *o, Value *values, uint n)
{
SimpleArrayData *dd = static_cast<SimpleArrayData *>(o->arrayData());
Q_ASSERT(!dd->attrs());
- for (int i = n - 1; i >= 0; --i) {
- if (!dd->offset()) {
- getHeadRoom(o);
- dd = static_cast<SimpleArrayData *>(o->arrayData());
- }
-
-
- --dd->offset();
- --dd->arrayData();
- ++dd->len();
- ++dd->alloc();
- *dd->arrayData() = values[i].asReturnedValue();
+ if (dd->len() + n > dd->alloc()) {
+ realloc(o, Simple, dd->len() + n, false);
+ dd = static_cast<SimpleArrayData *>(o->arrayData());
}
-
+ dd->d()->offset = (dd->d()->offset - n) % dd->d()->alloc;
+ dd->len() += n;
+ for (uint i = 0; i < n; ++i)
+ dd->data(i) = values[i].asReturnedValue();
}
ReturnedValue SimpleArrayData::pop_front(Object *o)
@@ -299,11 +288,9 @@ ReturnedValue SimpleArrayData::pop_front(Object *o)
if (!dd->len())
return Encode::undefined();
- ReturnedValue v = dd->arrayData()[0].isEmpty() ? Encode::undefined() : dd->arrayData()[0].asReturnedValue();
- ++dd->offset();
- ++dd->arrayData();
+ ReturnedValue v = dd->data(0).isEmpty() ? Encode::undefined() : dd->data(0).asReturnedValue();
+ dd->d()->offset = (dd->d()->offset + 1) % dd->d()->alloc;
--dd->len();
- --dd->alloc();
return v;
}
@@ -313,19 +300,17 @@ uint SimpleArrayData::truncate(Object *o, uint newLen)
if (dd->len() < newLen)
return newLen;
- if (dd->attrs()) {
- Value *it = dd->arrayData() + dd->len();
- const Value *begin = dd->arrayData() + newLen;
- while (--it >= begin) {
- if (!it->isEmpty() && !dd->attrs()[it - dd->arrayData()].isConfigurable()) {
- newLen = it - dd->arrayData() + 1;
- break;
- }
- *it = Primitive::emptyValue();
- }
+ if (!dd->attrs()) {
+ dd->len() = newLen;
+ return newLen;
}
- dd->len() = newLen;
- return newLen;
+
+ while (dd->len() > newLen) {
+ if (!dd->data(dd->len() - 1).isEmpty() && !dd->attrs()[dd->len() - 1].isConfigurable())
+ return dd->len();
+ --dd->len();
+ }
+ return dd->len();
}
uint SimpleArrayData::length(const ArrayData *d)
@@ -341,9 +326,9 @@ bool SimpleArrayData::putArray(Object *o, uint index, Value *values, uint n)
dd = static_cast<SimpleArrayData *>(o->arrayData());
}
for (uint i = dd->len(); i < index; ++i)
- dd->arrayData()[i] = Primitive::emptyValue();
+ dd->data(i) = Primitive::emptyValue();
for (uint i = 0; i < n; ++i)
- dd->arrayData()[index + i] = values[i];
+ dd->data(index + i) = values[i];
dd->len() = qMax(dd->len(), index + n);
return true;
}
@@ -385,7 +370,7 @@ void SparseArrayData::markObjects(Managed *d, ExecutionEngine *e)
ArrayData *SparseArrayData::reallocate(Object *o, uint n, bool enforceAttributes)
{
- realloc(o, Sparse, 0, n, enforceAttributes);
+ realloc(o, Sparse, n, enforceAttributes);
return o->arrayData();
}
@@ -397,12 +382,14 @@ uint SparseArrayData::allocate(Object *o, bool doubleSlot)
if (doubleSlot) {
uint *last = &dd->freeList();
while (1) {
- if (*last + 1 >= dd->alloc()) {
+ if (*last == UINT_MAX) {
reallocate(o, o->arrayData()->alloc() + 2, true);
dd = static_cast<SparseArrayData *>(o->arrayData());
last = &dd->freeList();
+ Q_ASSERT(*last != UINT_MAX);
}
+ Q_ASSERT(dd->arrayData()[*last].uint_32 != *last);
if (dd->arrayData()[*last].uint_32 == (*last + 1)) {
// found two slots in a row
uint idx = *last;
@@ -413,11 +400,12 @@ uint SparseArrayData::allocate(Object *o, bool doubleSlot)
last = &dd->arrayData()[*last].uint_32;
}
} else {
- if (dd->alloc() == dd->freeList()) {
- reallocate(o, o->arrayData()->alloc() + 2, false);
+ if (dd->freeList() == UINT_MAX) {
+ reallocate(o, o->arrayData()->alloc() + 1, false);
dd = static_cast<SparseArrayData *>(o->arrayData());
}
uint idx = dd->freeList();
+ Q_ASSERT(idx != UINT_MAX);
dd->freeList() = dd->arrayData()[idx].uint_32;
if (dd->attrs())
dd->attrs()[idx] = Attr_Data;
@@ -427,10 +415,11 @@ uint SparseArrayData::allocate(Object *o, bool doubleSlot)
ReturnedValue SparseArrayData::get(const ArrayData *d, uint index)
{
- SparseArrayNode *n = static_cast<const SparseArrayData *>(d)->sparse()->findNode(index);
- if (!n)
+ const SparseArrayData *s = static_cast<const SparseArrayData *>(d);
+ index = s->mappedIndex(index);
+ if (index == UINT_MAX)
return Primitive::emptyValue().asReturnedValue();
- return d->arrayData()[n->value].asReturnedValue();
+ return s->arrayData()[index].asReturnedValue();
}
bool SparseArrayData::put(Object *o, uint index, ValueRef value)
@@ -438,19 +427,21 @@ bool SparseArrayData::put(Object *o, uint index, ValueRef value)
if (value->isEmpty())
return true;
- SparseArrayNode *n = static_cast<SparseArrayData *>(o->arrayData())->sparse()->insert(index);
+ SparseArrayData *s = static_cast<SparseArrayData *>(o->arrayData());
+ SparseArrayNode *n = s->sparse()->insert(index);
Q_ASSERT(n->value == UINT_MAX || !o->arrayData()->attrs() || !o->arrayData()->attrs()[n->value].isAccessor());
if (n->value == UINT_MAX)
n->value = allocate(o);
- o->arrayData()->arrayData()[n->value] = value;
- if (o->arrayData()->attrs())
- o->arrayData()->attrs()[n->value] = Attr_Data;
+ s->arrayData()[n->value] = value;
+ if (s->attrs())
+ s->attrs()[n->value] = Attr_Data;
return true;
}
bool SparseArrayData::del(Object *o, uint index)
{
SparseArrayData *dd = static_cast<SparseArrayData *>(o->arrayData());
+
SparseArrayNode *n = dd->sparse()->findNode(index);
if (!n)
return true;
@@ -469,12 +460,12 @@ bool SparseArrayData::del(Object *o, uint index)
if (isAccessor) {
// free up both indices
- dd->arrayData()[pidx + 1].tag = Value::Undefined_Type;
+ dd->arrayData()[pidx + 1].tag = Value::Empty_Type;
dd->arrayData()[pidx + 1].uint_32 = static_cast<SparseArrayData *>(dd)->freeList();
dd->arrayData()[pidx].tag = Value::Undefined_Type;
dd->arrayData()[pidx].uint_32 = pidx + 1;
} else {
- dd->arrayData()[pidx].tag = Value::Undefined_Type;
+ dd->arrayData()[pidx].tag = Value::Empty_Type;
dd->arrayData()[pidx].uint_32 = static_cast<SparseArrayData *>(dd)->freeList();
}
@@ -509,21 +500,23 @@ PropertyAttributes SparseArrayData::attribute(const ArrayData *d, uint index)
void SparseArrayData::push_front(Object *o, Value *values, uint n)
{
+ SparseArrayData *d = static_cast<SparseArrayData *>(o->arrayData());
Q_ASSERT(!o->arrayData()->attrs());
for (int i = n - 1; i >= 0; --i) {
uint idx = allocate(o);
- o->arrayData()->arrayData()[idx] = values[i];
- static_cast<SparseArrayData *>(o->arrayData())->sparse()->push_front(idx);
+ d->arrayData()[idx] = values[i];
+ d->sparse()->push_front(idx);
}
}
ReturnedValue SparseArrayData::pop_front(Object *o)
{
+ SparseArrayData *d = static_cast<SparseArrayData *>(o->arrayData());
Q_ASSERT(!o->arrayData()->attrs());
- uint idx = static_cast<SparseArrayData *>(o->arrayData())->sparse()->pop_front();
+ uint idx = d->sparse()->pop_front();
ReturnedValue v;
if (idx != UINT_MAX) {
- v = o->arrayData()->arrayData()[idx].asReturnedValue();
+ v = d->arrayData()[idx].asReturnedValue();
free(o->arrayData(), idx);
} else {
v = Encode::undefined();
@@ -574,14 +567,14 @@ bool SparseArrayData::putArray(Object *o, uint index, Value *values, uint n)
}
-uint ArrayData::append(Object *obj, const ArrayObject *otherObj, uint n)
+uint ArrayData::append(Object *obj, ArrayObject *otherObj, uint n)
{
Q_ASSERT(!obj->arrayData()->hasAttributes());
if (!n)
return obj->getLength();
- const ArrayData *other = otherObj->arrayData();
+ ArrayData *other = otherObj->arrayData();
if (other->isSparse())
obj->initSparseArray();
@@ -591,21 +584,30 @@ uint ArrayData::append(Object *obj, const ArrayObject *otherObj, uint n)
uint oldSize = obj->getLength();
if (other->isSparse()) {
+ SparseArrayData *os = static_cast<SparseArrayData *>(other);
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->arrayData() + it->value), other->attrs()[it->value]);
+ for (const SparseArrayNode *it = os->sparse()->begin();
+ it != os->sparse()->end(); it = it->nextNode()) {
+ v = otherObj->getValue(reinterpret_cast<Property *>(os->arrayData() + it->value), other->attrs()[it->value]);
obj->arraySet(oldSize + it->key(), v);
}
} else {
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(), ValueRef(other->arrayData()[it->value]));
+ it != os->sparse()->end(); it = it->nextNode())
+ obj->arraySet(oldSize + it->key(), ValueRef(os->arrayData()[it->value]));
}
} else {
- obj->arrayPut(oldSize, other->arrayData(), n);
+ SimpleArrayData *os = static_cast<SimpleArrayData *>(other);
+ uint toCopy = n;
+ uint chunk = toCopy;
+ if (chunk > os->alloc() - os->d()->offset)
+ chunk -= os->alloc() - os->d()->offset;
+ obj->arrayPut(oldSize, os->arrayData() + os->d()->offset, chunk);
+ toCopy -= chunk;
+ if (toCopy)
+ obj->arrayPut(oldSize + chunk, os->arrayData(), toCopy);
}
return oldSize + n;
@@ -623,18 +625,19 @@ Property *ArrayData::insert(Object *o, uint index, bool isAccessor)
if (index >= d->len()) {
// mark possible hole in the array
for (uint i = d->len(); i < index; ++i)
- d->arrayData()[i] = Primitive::emptyValue();
+ d->data(i) = Primitive::emptyValue();
d->len() = index + 1;
}
- return reinterpret_cast<Property *>(o->arrayData()->arrayData() + index);
+ return reinterpret_cast<Property *>(d->d()->arrayData + d->mappedIndex(index));
}
}
o->initSparseArray();
- SparseArrayNode *n = static_cast<SparseArrayData *>(o->arrayData())->sparse()->insert(index);
+ SparseArrayData *s = static_cast<SparseArrayData *>(o->arrayData());
+ SparseArrayNode *n = s->sparse()->insert(index);
if (n->value == UINT_MAX)
n->value = SparseArrayData::allocate(o, isAccessor);
- return reinterpret_cast<Property *>(o->arrayData()->arrayData() + n->value);
+ return reinterpret_cast<Property *>(s->arrayData() + n->value);
}
@@ -737,7 +740,7 @@ void ArrayData::sort(ExecutionContext *context, Object *thisObject, const ValueR
if (!len)
return;
- if (!thisObject->arrayData()->length())
+ if (!thisObject->arrayData() || !thisObject->arrayData()->length())
return;
if (!(comparefn->isUndefined() || comparefn->asObject())) {
@@ -757,7 +760,7 @@ void ArrayData::sort(ExecutionContext *context, Object *thisObject, const ValueR
return;
thisObject->setArrayData(0);
- ArrayData::realloc(thisObject, ArrayData::Simple, 0, sparse->sparse()->nEntries(), sparse->attrs() ? true : false);
+ ArrayData::realloc(thisObject, ArrayData::Simple, sparse->sparse()->nEntries(), sparse->attrs() ? true : false);
SimpleArrayData *d = static_cast<SimpleArrayData *>(thisObject->arrayData());
SparseArrayNode *n = sparse->sparse()->begin();
@@ -768,7 +771,7 @@ void ArrayData::sort(ExecutionContext *context, Object *thisObject, const ValueR
break;
PropertyAttributes a = sparse->attrs() ? sparse->attrs()[n->value] : Attr_Data;
- d->arrayData()[i] = thisObject->getValue(reinterpret_cast<Property *>(sparse->arrayData() + n->value), a);
+ d->data(i) = thisObject->getValue(reinterpret_cast<Property *>(sparse->arrayData() + n->value), a);
d->attrs()[i] = a.isAccessor() ? Attr_Data : a;
n = n->nextNode();
@@ -778,7 +781,7 @@ void ArrayData::sort(ExecutionContext *context, Object *thisObject, const ValueR
while (n != sparse->sparse()->end()) {
if (n->value >= len)
break;
- d->arrayData()[i] = sparse->arrayData()[n->value];
+ d->data(i) = sparse->arrayData()[n->value];
n = n->nextNode();
++i;
}
@@ -805,13 +808,13 @@ void ArrayData::sort(ExecutionContext *context, Object *thisObject, const ValueR
// sort empty values to the end
for (uint i = 0; i < len; i++) {
- if (thisObject->arrayData()->arrayData()[i].isEmpty()) {
+ if (d->data(i).isEmpty()) {
while (--len > i)
- if (!thisObject->arrayData()->arrayData()[len].isEmpty())
+ if (!d->data(len).isEmpty())
break;
- Q_ASSERT(!thisObject->arrayData()->attrs() || !thisObject->arrayData()->attrs()[len].isAccessor());
- thisObject->arrayData()->arrayData()[i] = thisObject->arrayData()->arrayData()[len];
- thisObject->arrayData()->arrayData()[len] = Primitive::emptyValue();
+ Q_ASSERT(!d->attrs() || !d->attrs()[len].isAccessor());
+ d->data(i) = d->data(len);
+ d->data(len) = Primitive::emptyValue();
}
}
@@ -822,7 +825,7 @@ void ArrayData::sort(ExecutionContext *context, Object *thisObject, const ValueR
ArrayElementLessThan lessThan(context, thisObject, comparefn);
- Value *begin = thisObject->arrayData()->arrayData();
+ Value *begin = thisObject->arrayData()->d()->arrayData;
sortHelper(begin, begin + len, *begin, lessThan);
#ifdef CHECK_SPARSE_ARRAYS
diff --git a/src/qml/jsruntime/qv4arraydata_p.h b/src/qml/jsruntime/qv4arraydata_p.h
index 3b04fe973a..c2deb3e385 100644
--- a/src/qml/jsruntime/qv4arraydata_p.h
+++ b/src/qml/jsruntime/qv4arraydata_p.h
@@ -90,7 +90,15 @@ struct Q_QML_EXPORT ArrayData : public Managed
uint alloc;
Type type;
PropertyAttributes *attrs;
- Value *arrayData;
+ union {
+ uint len;
+ uint freeList;
+ };
+ union {
+ uint offset;
+ SparseArray *sparse;
+ };
+ Value arrayData[1];
};
V4_MANAGED(Managed)
@@ -101,16 +109,13 @@ struct Q_QML_EXPORT ArrayData : public Managed
void setType(Type t) { d()->type = t; }
PropertyAttributes *attrs() const { return d()->attrs; }
void setAttrs(PropertyAttributes *a) { d()->attrs = a; }
- Value *arrayData() const { return d()->arrayData; }
- Value *&arrayData() { return d()->arrayData; }
- void setArrayData(Value *v) { d()->arrayData = v; }
+ const Value *arrayData() const { return &d()->arrayData[0]; }
+ Value *arrayData() { return &d()->arrayData[0]; }
const ArrayVTable *vtable() const { return reinterpret_cast<const ArrayVTable *>(internalClass()->vtable); }
bool isSparse() const { return this && type() == Sparse; }
uint length() const {
- if (!this)
- return 0;
return vtable()->length(this);
}
@@ -123,23 +128,19 @@ struct Q_QML_EXPORT ArrayData : public Managed
}
bool isEmpty(uint i) const {
- if (!this)
- return true;
return (vtable()->get(this, i) == Primitive::emptyValue().asReturnedValue());
}
ReturnedValue get(uint i) const {
- if (!this)
- return Primitive::emptyValue().asReturnedValue();
return vtable()->get(this, i);
}
- inline Property *getProperty(uint index) const;
+ inline Property *getProperty(uint index);
static void ensureAttributes(Object *o);
- static void realloc(Object *o, Type newType, uint offset, uint alloc, bool enforceAttributes);
+ static void realloc(Object *o, Type newType, uint alloc, bool enforceAttributes);
static void sort(ExecutionContext *context, Object *thisObject, const ValueRef comparefn, uint dataLen);
- static uint append(Object *obj, const ArrayObject *otherObj, uint n);
+ static uint append(Object *obj, ArrayObject *otherObj, uint n);
static Property *insert(Object *o, uint index, bool isAccessor = false);
};
@@ -150,17 +151,25 @@ struct Q_QML_EXPORT SimpleArrayData : public ArrayData
Data(ExecutionEngine *engine)
: ArrayData::Data(engine->simpleArrayDataClass)
{}
- uint len;
- uint offset;
};
V4_ARRAYDATA
+ uint mappedIndex(uint index) const { return (index + d()->offset) % d()->alloc; }
+ Value data(uint index) const { return d()->arrayData[mappedIndex(index)]; }
+ Value &data(uint index) { return d()->arrayData[mappedIndex(index)]; }
+
+ Property *getProperty(uint index) {
+ if (index >= len())
+ return 0;
+ index = mappedIndex(index);
+ if (d()->arrayData[index].isEmpty())
+ return 0;
+ return reinterpret_cast<Property *>(d()->arrayData + index);
+ }
+
uint &len() { return d()->len; }
uint len() const { return d()->len; }
- uint &offset() { return d()->offset; }
- uint offset() const { return d()->offset; }
- static void getHeadRoom(Object *o);
static ArrayData *reallocate(Object *o, uint n, bool enforceAttributes);
static void markObjects(Managed *d, ExecutionEngine *e);
@@ -183,9 +192,6 @@ struct Q_QML_EXPORT SparseArrayData : public ArrayData
Data(ExecutionEngine *engine)
: ArrayData::Data(engine->emptyClass)
{ setVTable(staticVTable()); }
-
- uint freeList;
- SparseArray *sparse;
};
V4_ARRAYDATA
@@ -197,6 +203,20 @@ struct Q_QML_EXPORT SparseArrayData : public ArrayData
static uint allocate(Object *o, bool doubleSlot = false);
static void free(ArrayData *d, uint idx);
+ Property *getProperty(uint index) {
+ SparseArrayNode *n = sparse()->findNode(index);
+ if (!n)
+ return 0;
+ return reinterpret_cast<Property *>(arrayData() + n->value);
+ }
+
+ uint mappedIndex(uint index) const {
+ SparseArrayNode *n = sparse()->findNode(index);
+ if (!n)
+ return UINT_MAX;
+ return n->value;
+ }
+
static void destroy(Managed *d);
static void markObjects(Managed *d, ExecutionEngine *e);
@@ -214,20 +234,14 @@ struct Q_QML_EXPORT SparseArrayData : public ArrayData
};
-inline Property *ArrayData::getProperty(uint index) const
+inline Property *ArrayData::getProperty(uint index)
{
- if (!this)
- return 0;
if (type() != Sparse) {
- const SimpleArrayData *that = static_cast<const SimpleArrayData *>(this);
- if (index >= that->len() || arrayData()[index].isEmpty())
- return 0;
- return reinterpret_cast<Property *>(arrayData() + index);
+ SimpleArrayData *that = static_cast<SimpleArrayData *>(this);
+ return that->getProperty(index);
} else {
- SparseArrayNode *n = static_cast<const SparseArrayData *>(this)->sparse()->findNode(index);
- if (!n)
- return 0;
- return reinterpret_cast<Property *>(arrayData() + n->value);
+ SparseArrayData *that = static_cast<SparseArrayData *>(this);
+ return that->getProperty(index);
}
}
diff --git a/src/qml/jsruntime/qv4arrayobject.cpp b/src/qml/jsruntime/qv4arrayobject.cpp
index 7515a839ce..011279ae07 100644
--- a/src/qml/jsruntime/qv4arrayobject.cpp
+++ b/src/qml/jsruntime/qv4arrayobject.cpp
@@ -268,6 +268,7 @@ ReturnedValue ArrayPrototype::method_push(CallContext *ctx)
return Encode::undefined();
instance->arrayCreate();
+ Q_ASSERT(instance->arrayData());
uint len = instance->getLength();
@@ -347,6 +348,7 @@ ReturnedValue ArrayPrototype::method_shift(CallContext *ctx)
return Encode::undefined();
instance->arrayCreate();
+ Q_ASSERT(instance->arrayData());
uint len = instance->getLength();
@@ -534,6 +536,7 @@ ReturnedValue ArrayPrototype::method_unshift(CallContext *ctx)
return Encode::undefined();
instance->arrayCreate();
+ Q_ASSERT(instance->arrayData());
uint len = instance->getLength();
@@ -614,20 +617,17 @@ ReturnedValue ArrayPrototype::method_indexOf(CallContext *ctx)
return Encode(-1);
} else {
Q_ASSERT(instance->arrayType() == ArrayData::Simple || instance->arrayType() == ArrayData::Complex);
- if (len > instance->arrayData()->length())
- len = instance->arrayData()->length();
- Value *val = instance->arrayData()->arrayData();
- Value *end = val + len;
- val += fromIndex;
- while (val < end) {
- if (!val->isEmpty()) {
- value = *val;
- if (scope.hasException())
- return Encode::undefined();
- if (RuntimeHelpers::strictEqual(value, searchValue))
- return Encode((uint)(val - instance->arrayData()->arrayData()));
- }
- ++val;
+ SimpleArrayData *sa = static_cast<SimpleArrayData *>(instance->arrayData());
+ if (len > sa->len())
+ len = sa->len();
+ uint idx = fromIndex;
+ while (idx < len) {
+ value = sa->data(idx);
+ if (scope.hasException())
+ return Encode::undefined();
+ if (RuntimeHelpers::strictEqual(value, searchValue))
+ return Encode(idx);
+ ++idx;
}
}
return Encode(-1);
diff --git a/src/qml/jsruntime/qv4dateobject.cpp b/src/qml/jsruntime/qv4dateobject.cpp
index 66601b64e5..e00a705700 100644
--- a/src/qml/jsruntime/qv4dateobject.cpp
+++ b/src/qml/jsruntime/qv4dateobject.cpp
@@ -557,7 +557,13 @@ static inline QString ToString(double t)
{
if (std::isnan(t))
return QStringLiteral("Invalid Date");
- QString str = ToDateTime(t, Qt::LocalTime).toString() + QStringLiteral(" GMT");
+ QDateTime dateTime = ToDateTime(t, Qt::LocalTime);
+
+ // JavaScript knows a year 0, while QDateTime doesn't. So, in order to show the right date we
+ // have to add a year to negative ones here.
+ if (dateTime.date().year() < 0)
+ dateTime = dateTime.addYears(1);
+ QString str = dateTime.toString() + QStringLiteral(" GMT");
double tzoffset = LocalTZA + DaylightSavingTA(t);
if (tzoffset) {
int hours = static_cast<int>(::fabs(tzoffset) / 1000 / 60 / 60);
diff --git a/src/qml/jsruntime/qv4functionobject.cpp b/src/qml/jsruntime/qv4functionobject.cpp
index cddc45aaf5..f3ad8ef892 100644
--- a/src/qml/jsruntime/qv4functionobject.cpp
+++ b/src/qml/jsruntime/qv4functionobject.cpp
@@ -108,7 +108,7 @@ FunctionObject::Data::Data(InternalClass *ic)
FunctionObject::Data::~Data()
{
if (function)
- function->compilationUnit->deref();
+ function->compilationUnit->release();
}
void FunctionObject::init(String *n, bool createProto)
@@ -226,7 +226,7 @@ ReturnedValue FunctionCtor::construct(Managed *that, CallData *callData)
QV4::Compiler::JSUnitGenerator jsGenerator(&module);
QScopedPointer<EvalInstructionSelection> isel(v4->iselFactory->create(QQmlEnginePrivate::get(v4), v4->executableAllocator, &module, &jsGenerator));
- QV4::CompiledData::CompilationUnit *compilationUnit = isel->compile();
+ QQmlRefPointer<QV4::CompiledData::CompilationUnit> compilationUnit = isel->compile();
QV4::Function *vmf = compilationUnit->linkToEngine(v4);
return FunctionObject::createScriptFunction(v4->rootContext, vmf)->asReturnedValue();
@@ -298,9 +298,11 @@ ReturnedValue FunctionPrototype::method_apply(CallContext *ctx)
for (quint32 i = 0; i < len; ++i)
callData->args[i] = arr->getIndexed(i);
} else {
- int alen = qMin(len, arr->arrayData()->length());
- if (alen)
- memcpy(callData->args, arr->arrayData()->arrayData(), alen*sizeof(Value));
+ uint alen = arr->arrayData() ? arr->arrayData()->length() : 0;
+ if (alen > len)
+ alen = len;
+ for (uint i = 0; i < alen; ++i)
+ callData->args[i] = static_cast<SimpleArrayData *>(arr->arrayData())->data(i);
for (quint32 i = alen; i < len; ++i)
callData->args[i] = Primitive::undefinedValue();
}
@@ -416,7 +418,7 @@ SimpleScriptFunction::Data::Data(ExecutionContext *scope, Function *function, bo
setVTable(staticVTable());
this->function = function;
- function->compilationUnit->ref();
+ function->compilationUnit->addref();
Q_ASSERT(function);
Q_ASSERT(function->code);
diff --git a/src/qml/jsruntime/qv4lookup.cpp b/src/qml/jsruntime/qv4lookup.cpp
index 6d4f05d8d4..254666eca2 100644
--- a/src/qml/jsruntime/qv4lookup.cpp
+++ b/src/qml/jsruntime/qv4lookup.cpp
@@ -139,7 +139,7 @@ ReturnedValue Lookup::indexedGetterFallback(Lookup *l, const ValueRef object, co
}
if (idx < UINT_MAX) {
- if (!o->arrayData()->hasAttributes()) {
+ if (o->arrayData() && !o->arrayData()->hasAttributes()) {
ScopedValue v(scope, o->arrayData()->get(idx));
if (!v->isEmpty())
return v->asReturnedValue();
@@ -164,9 +164,10 @@ ReturnedValue Lookup::indexedGetterObjectInt(Lookup *l, const ValueRef object, c
Object *o = object->objectValue();
if (o->arrayData() && o->arrayData()->type() == ArrayData::Simple) {
- if (idx < static_cast<SimpleArrayData *>(o->arrayData())->len())
- if (!o->arrayData()->arrayData()[idx].isEmpty())
- return o->arrayData()->arrayData()[idx].asReturnedValue();
+ SimpleArrayData *s = static_cast<SimpleArrayData *>(o->arrayData());
+ if (idx < s->len())
+ if (!s->data(idx).isEmpty())
+ return s->data(idx).asReturnedValue();
}
return indexedGetterFallback(l, object, index);
@@ -197,8 +198,8 @@ void Lookup::indexedSetterFallback(Lookup *l, const ValueRef object, const Value
if (idx < UINT_MAX) {
if (o->arrayData() && o->arrayData()->type() == ArrayData::Simple) {
SimpleArrayData *s = static_cast<SimpleArrayData *>(o->arrayData());
- if (s && idx < s->len() && !s->arrayData()[idx].isEmpty()) {
- s->arrayData()[idx] = value;
+ if (idx < s->len() && !s->data(idx).isEmpty()) {
+ s->data(idx) = value;
return;
}
}
@@ -221,8 +222,8 @@ void Lookup::indexedSetterObjectInt(Lookup *l, const ValueRef object, const Valu
Object *o = object->objectValue();
if (o->arrayData() && o->arrayData()->type() == ArrayData::Simple) {
SimpleArrayData *s = static_cast<SimpleArrayData *>(o->arrayData());
- if (idx < s->len() && !s->arrayData()[idx].isEmpty()) {
- s->arrayData()[idx] = v;
+ if (idx < s->len() && !s->data(idx).isEmpty()) {
+ s->data(idx) = v;
return;
}
}
diff --git a/src/qml/jsruntime/qv4mm.cpp b/src/qml/jsruntime/qv4mm.cpp
index 0cb10b1506..b9a4a55b4a 100644
--- a/src/qml/jsruntime/qv4mm.cpp
+++ b/src/qml/jsruntime/qv4mm.cpp
@@ -104,6 +104,7 @@ struct MemoryManager::Data
};
LargeItem *largeItems;
+ std::size_t totalLargeItemsAllocated;
GCDeletable *deletable;
@@ -120,6 +121,7 @@ struct MemoryManager::Data
, maxShift(6)
, maxChunkSize(32*1024)
, largeItems(0)
+ , totalLargeItemsAllocated(0)
, deletable(0)
{
memset(smallItems, 0, sizeof(smallItems));
@@ -185,6 +187,9 @@ Managed *MemoryManager::allocData(std::size_t size)
// doesn't fit into a small bucket
if (size >= MemoryManager::Data::MaxItemSize) {
+ if (m_d->totalLargeItemsAllocated > 8 * 1024 * 1024)
+ runGC();
+
// we use malloc for this
MemoryManager::Data::LargeItem *item = static_cast<MemoryManager::Data::LargeItem *>(
malloc(Q_V4_PROFILE_ALLOC(m_d->engine, size + sizeof(MemoryManager::Data::LargeItem),
@@ -193,6 +198,7 @@ Managed *MemoryManager::allocData(std::size_t size)
item->next = m_d->largeItems;
item->size = size;
m_d->largeItems = item;
+ m_d->totalLargeItemsAllocated += size;
return item->managed();
}
@@ -255,6 +261,15 @@ Managed *MemoryManager::allocData(std::size_t size)
return m;
}
+static void drainMarkStack(QV4::ExecutionEngine *engine, Value *markBase)
+{
+ while (engine->jsStackTop > markBase) {
+ Managed *m = engine->popForGC();
+ Q_ASSERT (m->internalClass()->vtable->markObjects);
+ m->internalClass()->vtable->markObjects(m, engine);
+ }
+}
+
void MemoryManager::mark()
{
Value *markBase = m_d->engine->jsStackTop;
@@ -272,6 +287,9 @@ void MemoryManager::mark()
}
persistent->value.mark(m_d->engine);
persistent = persistent->next;
+
+ if (m_d->engine->jsStackTop >= m_d->engine->jsStackLimit)
+ drainMarkStack(m_d->engine, markBase);
}
collectFromJSStack();
@@ -304,14 +322,12 @@ void MemoryManager::mark()
if (keepAlive)
qobjectWrapper->getPointer()->mark(m_d->engine);
- }
- // now that we marked all roots, start marking recursively and popping from the mark stack
- while (m_d->engine->jsStackTop > markBase) {
- Managed *m = m_d->engine->popForGC();
- Q_ASSERT (m->internalClass()->vtable->markObjects);
- m->internalClass()->vtable->markObjects(m, m_d->engine);
+ if (m_d->engine->jsStackTop >= m_d->engine->jsStackLimit)
+ drainMarkStack(m_d->engine, markBase);
}
+
+ drainMarkStack(m_d->engine, markBase);
}
void MemoryManager::sweep(bool lastSweep)
@@ -466,6 +482,7 @@ void MemoryManager::runGC()
memset(m_d->allocCount, 0, sizeof(m_d->allocCount));
m_d->totalAlloc = 0;
+ m_d->totalLargeItemsAllocated = 0;
}
size_t MemoryManager::getUsedMem() const
diff --git a/src/qml/jsruntime/qv4object.cpp b/src/qml/jsruntime/qv4object.cpp
index 6d78c89d89..0c61d666ab 100644
--- a/src/qml/jsruntime/qv4object.cpp
+++ b/src/qml/jsruntime/qv4object.cpp
@@ -244,7 +244,7 @@ Property *Object::__getOwnProperty__(String *name, PropertyAttributes *attrs)
Property *Object::__getOwnProperty__(uint index, PropertyAttributes *attrs)
{
- Property *p = arrayData()->getProperty(index);
+ Property *p = arrayData() ? arrayData()->getProperty(index) : 0;
if (p) {
if (attrs)
*attrs = arrayData()->attributes(index);
@@ -289,7 +289,7 @@ Property *Object::__getPropertyDescriptor__(uint index, PropertyAttributes *attr
{
const Object *o = this;
while (o) {
- Property *p = o->arrayData()->getProperty(index);
+ Property *p = o->arrayData() ? o->arrayData()->getProperty(index) : 0;
if (p) {
if (attrs)
*attrs = o->arrayData()->attributes(index);
@@ -355,7 +355,7 @@ bool Object::hasOwnProperty(String *name) const
bool Object::hasOwnProperty(uint index) const
{
- if (!arrayData()->isEmpty(index))
+ if (arrayData() && !arrayData()->isEmpty(index))
return true;
if (isStringObject()) {
String *s = static_cast<const StringObject *>(this)->d()->value.asString();
@@ -414,7 +414,7 @@ PropertyAttributes Object::query(const Managed *m, String *name)
PropertyAttributes Object::queryIndexed(const Managed *m, uint index)
{
const Object *o = static_cast<const Object *>(m);
- if (o->arrayData()->get(index) != Primitive::emptyValue().asReturnedValue())
+ if (o->arrayData() && o->arrayData()->get(index) != Primitive::emptyValue().asReturnedValue())
return o->arrayData()->attributes(index);
if (o->isStringObject()) {
@@ -533,7 +533,8 @@ void Object::advanceIterator(Managed *m, ObjectIterator *it, String *&name, uint
while (it->arrayNode != o->sparseEnd()) {
int k = it->arrayNode->key();
uint pidx = it->arrayNode->value;
- Property *p = reinterpret_cast<Property *>(o->arrayData()->arrayData() + pidx);
+ SparseArrayData *sa = static_cast<SparseArrayData *>(o->arrayData());
+ Property *p = reinterpret_cast<Property *>(sa->arrayData() + pidx);
it->arrayNode = it->arrayNode->nextNode();
PropertyAttributes a = o->arrayData()->attributes(k);
if (!(it->flags & ObjectIterator::EnumerableOnly) || a.isEnumerable()) {
@@ -549,14 +550,15 @@ void Object::advanceIterator(Managed *m, ObjectIterator *it, String *&name, uint
}
// dense arrays
while (it->arrayIndex < o->arrayData()->length()) {
- Value *val = o->arrayData()->arrayData() + it->arrayIndex;
+ SimpleArrayData *sa = static_cast<SimpleArrayData *>(o->arrayData());
+ Value &val = sa->data(it->arrayIndex);
PropertyAttributes a = o->arrayData()->attributes(it->arrayIndex);
++it->arrayIndex;
- if (!val->isEmpty()
+ if (!val.isEmpty()
&& (!(it->flags & ObjectIterator::EnumerableOnly) || a.isEnumerable())) {
*index = it->arrayIndex - 1;
*attrs = a;
- pd->value = *val;
+ pd->value = val;
return;
}
}
@@ -616,7 +618,7 @@ ReturnedValue Object::internalGetIndexed(uint index, bool *hasProperty)
PropertyAttributes attrs;
Object *o = this;
while (o) {
- Property *p = o->arrayData()->getProperty(index);
+ Property *p = o->arrayData() ? o->arrayData()->getProperty(index) : 0;
if (p) {
pd = p;
attrs = o->arrayData()->attributes(index);
@@ -736,7 +738,7 @@ void Object::internalPutIndexed(uint index, const ValueRef value)
PropertyAttributes attrs;
- Property *pd = arrayData()->getProperty(index);
+ Property *pd = arrayData() ? arrayData()->getProperty(index) : 0;
if (pd)
attrs = arrayData()->attributes(index);
@@ -923,7 +925,7 @@ bool Object::defineOwnProperty2(ExecutionContext *ctx, uint index, const Propert
Property *current = 0;
// Clause 1
- {
+ if (arrayData()) {
current = arrayData()->getProperty(index);
if (!current && isStringObject())
current = static_cast<StringObject *>(this)->getIndex(index);
@@ -960,12 +962,12 @@ bool Object::__defineOwnProperty__(ExecutionContext *ctx, uint index, String *me
if (attrs.isEmpty())
return true;
- Property *current;
+ Property *current = 0;
PropertyAttributes cattrs;
if (member) {
current = propertyAt(index);
cattrs = internalClass()->propertyData[index];
- } else {
+ } else if (arrayData()) {
current = arrayData()->getProperty(index);
cattrs = arrayData()->attributes(index);
}
@@ -998,6 +1000,7 @@ bool Object::__defineOwnProperty__(ExecutionContext *ctx, uint index, String *me
if (!member) {
// need to convert the array and the slot
initSparseArray();
+ Q_ASSERT(arrayData());
setArrayAttributes(index, cattrs);
current = arrayData()->getProperty(index);
}
@@ -1073,14 +1076,14 @@ 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()) {
- v = other->getValue(reinterpret_cast<Property *>(other->arrayData()->arrayData() + it->value), other->arrayData()->attrs()[it->value]);
+ SparseArrayData *osa = static_cast<SparseArrayData *>(other->arrayData());
+ for (const SparseArrayNode *it = osa->sparse()->begin(); it != osa->sparse()->end(); it = it->nextNode()) {
+ v = other->getValue(reinterpret_cast<Property *>(osa->arrayData() + it->value), other->arrayData()->attrs()[it->value]);
arraySet(it->key(), v);
}
} else {
Q_ASSERT(!arrayData() && other->arrayData());
- ArrayData::realloc(this, other->arrayData()->type(), 0, other->arrayData()->alloc(), other->arrayData()->attrs());
+ ArrayData::realloc(this, other->arrayData()->type(), other->arrayData()->alloc(), false);
if (other->arrayType() == ArrayData::Sparse) {
SparseArrayData *od = static_cast<SparseArrayData *>(other->arrayData());
SparseArrayData *dd = static_cast<SparseArrayData *>(arrayData());
@@ -1089,9 +1092,9 @@ void Object::copyArrayData(Object *other)
} else {
SimpleArrayData *d = static_cast<SimpleArrayData *>(arrayData());
d->len() = static_cast<SimpleArrayData *>(other->arrayData())->len();
- d->offset() = 0;
+ d->d()->offset = static_cast<SimpleArrayData *>(other->arrayData())->d()->offset;
}
- memcpy(arrayData()->arrayData(), other->arrayData()->arrayData(), arrayData()->alloc()*sizeof(Value));
+ memcpy(arrayData()->d()->arrayData, other->arrayData()->d()->arrayData, arrayData()->alloc()*sizeof(Value));
}
setArrayLengthUnchecked(other->getLength());
}
@@ -1132,7 +1135,7 @@ void Object::initSparseArray()
if (arrayType() == ArrayData::Sparse)
return;
- ArrayData::realloc(this, ArrayData::Sparse, 0, 0, false);
+ ArrayData::realloc(this, ArrayData::Sparse, 0, false);
}
diff --git a/src/qml/jsruntime/qv4object_p.h b/src/qml/jsruntime/qv4object_p.h
index 77debf121c..4e9d1527c2 100644
--- a/src/qml/jsruntime/qv4object_p.h
+++ b/src/qml/jsruntime/qv4object_p.h
@@ -114,8 +114,7 @@ struct Q_QML_EXPORT Object: Managed {
Members &memberData() { return d()->memberData; }
const Members &memberData() const { return d()->memberData; }
- const ArrayData *arrayData() const { return d()->arrayData; }
- ArrayData *arrayData() { return d()->arrayData; }
+ ArrayData *arrayData() const { return d()->arrayData; }
void setArrayData(ArrayData *a) { d()->arrayData = a; }
Property *propertyAt(uint index) const { return reinterpret_cast<Property *>(memberData().data() + index); }
@@ -222,12 +221,12 @@ public:
}
inline void arrayReserve(uint n) {
- ArrayData::realloc(this, ArrayData::Simple, 0, n, false);
+ ArrayData::realloc(this, ArrayData::Simple, n, false);
}
void arrayCreate() {
if (!arrayData())
- ArrayData::realloc(this, ArrayData::Simple, 0, 0, false);
+ ArrayData::realloc(this, ArrayData::Simple, 0, false);
#ifdef CHECK_SPARSE_ARRAYS
initSparseArray();
#endif
diff --git a/src/qml/jsruntime/qv4objectiterator.cpp b/src/qml/jsruntime/qv4objectiterator.cpp
index daee44cfb6..f9038472df 100644
--- a/src/qml/jsruntime/qv4objectiterator.cpp
+++ b/src/qml/jsruntime/qv4objectiterator.cpp
@@ -46,17 +46,7 @@ ObjectIterator::ObjectIterator(Value *scratch1, Value *scratch2, Object *o, uint
, memberIndex(0)
, flags(flags)
{
- object->o = o;
- current->o = o;
-#if QT_POINTER_SIZE == 4
- object->tag = QV4::Value::Managed_Type;
- current->tag = QV4::Value::Managed_Type;
-#endif
-
- if (object->as<ArgumentsObject>()) {
- Scope scope(object->engine());
- Scoped<ArgumentsObject> (scope, object->asReturnedValue())->fullyCreate();
- }
+ init(o);
}
ObjectIterator::ObjectIterator(Scope &scope, Object *o, uint flags)
@@ -67,8 +57,27 @@ ObjectIterator::ObjectIterator(Scope &scope, Object *o, uint flags)
, memberIndex(0)
, flags(flags)
{
+ init(o);
+}
+
+ObjectIterator::ObjectIterator(Value *scratch1, Value *scratch2, uint flags)
+ : object(scratch1)
+ , current(scratch2)
+ , arrayNode(0)
+ , arrayIndex(0)
+ , memberIndex(0)
+ , flags(flags)
+{
+ object->o = (Object*)0;
+ current->o = (Object*)0;
+ // Caller needs to call init!
+}
+
+void ObjectIterator::init(Object *o)
+{
object->o = o;
current->o = o;
+
#if QT_POINTER_SIZE == 4
object->tag = QV4::Value::Managed_Type;
current->tag = QV4::Value::Managed_Type;
diff --git a/src/qml/jsruntime/qv4objectiterator_p.h b/src/qml/jsruntime/qv4objectiterator_p.h
index 4bb164ed0c..3ed73b5c08 100644
--- a/src/qml/jsruntime/qv4objectiterator_p.h
+++ b/src/qml/jsruntime/qv4objectiterator_p.h
@@ -50,6 +50,7 @@ struct ExecutionContext;
struct Property;
struct String;
struct InternalClass;
+struct ForEachIteratorObject;
struct Q_QML_EXPORT ObjectIterator
{
@@ -68,10 +69,14 @@ struct Q_QML_EXPORT ObjectIterator
ObjectIterator(Value *scratch1, Value *scratch2, Object *o, uint flags);
ObjectIterator(Scope &scope, Object *o, uint flags);
+ void init(Object *o);
void next(String *&name, uint *index, Property *pd, PropertyAttributes *attributes = 0);
ReturnedValue nextPropertyName(ValueRef value);
ReturnedValue nextPropertyNameAsString(ValueRef value);
ReturnedValue nextPropertyNameAsString();
+private:
+ friend struct ForEachIteratorObject;
+ ObjectIterator(Value *scratch1, Value *scratch2, uint flags); // Constructor that requires calling init()
};
struct ForEachIteratorObject: Object {
diff --git a/src/qml/jsruntime/qv4objectproto.cpp b/src/qml/jsruntime/qv4objectproto.cpp
index a1c61307d1..9cbf4b204e 100644
--- a/src/qml/jsruntime/qv4objectproto.cpp
+++ b/src/qml/jsruntime/qv4objectproto.cpp
@@ -329,11 +329,11 @@ ReturnedValue ObjectPrototype::method_isSealed(CallContext *ctx)
if (!o->arrayData() || !o->arrayData()->length())
return Encode(true);
- if (o->arrayData()->length() && !o->arrayData()->attrs())
+ Q_ASSERT(o->arrayData() && o->arrayData()->length());
+ if (!o->arrayData()->attrs())
return Encode(false);
for (uint i = 0; i < o->arrayData()->alloc(); ++i) {
- // ### Fix for sparse arrays
if (!o->arrayData()->isEmpty(i))
if (o->arrayData()->attributes(i).isConfigurable())
return Encode(false);
@@ -355,14 +355,14 @@ ReturnedValue ObjectPrototype::method_isFrozen(CallContext *ctx)
if (o->internalClass() != o->internalClass()->frozen())
return Encode(false);
- if (!o->arrayData()->length())
+ if (!o->arrayData() || !o->arrayData()->length())
return Encode(true);
- if (o->arrayData()->length() && !o->arrayData()->attrs())
+ Q_ASSERT(o->arrayData() && o->arrayData()->length());
+ if (!o->arrayData()->attrs())
return Encode(false);
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())
return Encode(false);
diff --git a/src/qml/jsruntime/qv4profiling_p.h b/src/qml/jsruntime/qv4profiling_p.h
index 8224f8a851..7c66ee0049 100644
--- a/src/qml/jsruntime/qv4profiling_p.h
+++ b/src/qml/jsruntime/qv4profiling_p.h
@@ -80,23 +80,23 @@ public:
FunctionCall(Function *function, qint64 start, qint64 end) :
m_function(function), m_start(start), m_end(end)
- { m_function->compilationUnit->ref(); }
+ { m_function->compilationUnit->addref(); }
FunctionCall(const FunctionCall &other) :
m_function(other.m_function), m_start(other.m_start), m_end(other.m_end)
- { m_function->compilationUnit->ref(); }
+ { m_function->compilationUnit->addref(); }
~FunctionCall()
- { m_function->compilationUnit->deref(); }
+ { m_function->compilationUnit->release(); }
FunctionCall &operator=(const FunctionCall &other) {
if (&other != this) {
if (m_function)
- m_function->compilationUnit->deref();
+ m_function->compilationUnit->release();
m_function = other.m_function;
m_start = other.m_start;
m_end = other.m_end;
- m_function->compilationUnit->ref();
+ m_function->compilationUnit->addref();
}
return *this;
}
diff --git a/src/qml/jsruntime/qv4runtime.cpp b/src/qml/jsruntime/qv4runtime.cpp
index 55047e1cf9..048ff935bf 100644
--- a/src/qml/jsruntime/qv4runtime.cpp
+++ b/src/qml/jsruntime/qv4runtime.cpp
@@ -580,7 +580,7 @@ ReturnedValue Runtime::getElement(ExecutionContext *ctx, const ValueRef object,
}
if (idx < UINT_MAX) {
- if (!o->arrayData()->hasAttributes()) {
+ if (o->arrayData() && !o->arrayData()->hasAttributes()) {
ScopedValue v(scope, o->arrayData()->get(idx));
if (!v->isEmpty())
return v->asReturnedValue();
@@ -606,8 +606,8 @@ void Runtime::setElement(ExecutionContext *ctx, const ValueRef object, const Val
if (idx < UINT_MAX) {
if (o->arrayType() == ArrayData::Simple) {
SimpleArrayData *s = static_cast<SimpleArrayData *>(o->arrayData());
- if (s && idx < s->len() && !s->arrayData()[idx].isEmpty()) {
- s->arrayData()[idx] = value;
+ if (s && idx < s->len() && !s->data(idx).isEmpty()) {
+ s->data(idx) = value;
return;
}
}
diff --git a/src/qml/jsruntime/qv4script.cpp b/src/qml/jsruntime/qv4script.cpp
index 8e91c0e6a5..fa4b4b1894 100644
--- a/src/qml/jsruntime/qv4script.cpp
+++ b/src/qml/jsruntime/qv4script.cpp
@@ -62,7 +62,7 @@ QmlBindingWrapper::Data::Data(ExecutionContext *scope, Function *f, Object *qml)
setVTable(staticVTable());
function = f;
if (function)
- function->compilationUnit->ref();
+ function->compilationUnit->addref();
needsActivation = function ? function->needsActivation() : false;
Scope s(scope);
@@ -163,14 +163,9 @@ struct CompilationUnitHolder : public Object
: Object::Data(engine)
, unit(unit)
{
- unit->ref();
setVTable(staticVTable());
}
- ~Data()
- {
- unit->deref();
- }
- QV4::CompiledData::CompilationUnit *unit;
+ QQmlRefPointer<QV4::CompiledData::CompilationUnit> unit;
};
V4_OBJECT(Object)
@@ -264,7 +259,7 @@ void Script::parse()
QScopedPointer<EvalInstructionSelection> isel(v4->iselFactory->create(QQmlEnginePrivate::get(v4), v4->executableAllocator, &module, &jsGenerator));
if (inheritContext)
isel->setUseFastLookups(false);
- QV4::CompiledData::CompilationUnit *compilationUnit = isel->compile();
+ QQmlRefPointer<QV4::CompiledData::CompilationUnit> compilationUnit = isel->compile();
vmFunction = compilationUnit->linkToEngine(v4);
ScopedObject holder(valueScope, v4->memoryManager->alloc<CompilationUnitHolder>(v4, compilationUnit));
compilationUnitHolder = holder.asReturnedValue();
@@ -313,7 +308,7 @@ Function *Script::function()
return vmFunction;
}
-QV4::CompiledData::CompilationUnit *Script::precompile(IR::Module *module, Compiler::JSUnitGenerator *unitGenerator, ExecutionEngine *engine, const QUrl &url, const QString &source, QList<QQmlError> *reportedErrors)
+QQmlRefPointer<QV4::CompiledData::CompilationUnit> Script::precompile(IR::Module *module, Compiler::JSUnitGenerator *unitGenerator, ExecutionEngine *engine, const QUrl &url, const QString &source, QList<QQmlError> *reportedErrors)
{
using namespace QQmlJS;
using namespace QQmlJS::AST;
diff --git a/src/qml/jsruntime/qv4script_p.h b/src/qml/jsruntime/qv4script_p.h
index 28ac5f3e01..ed93ce49ae 100644
--- a/src/qml/jsruntime/qv4script_p.h
+++ b/src/qml/jsruntime/qv4script_p.h
@@ -122,7 +122,7 @@ struct Q_QML_EXPORT Script {
Function *function();
- static QV4::CompiledData::CompilationUnit *precompile(IR::Module *module, Compiler::JSUnitGenerator *unitGenerator, ExecutionEngine *engine, const QUrl &url, const QString &source, QList<QQmlError> *reportedErrors = 0);
+ static QQmlRefPointer<CompiledData::CompilationUnit> precompile(IR::Module *module, Compiler::JSUnitGenerator *unitGenerator, ExecutionEngine *engine, const QUrl &url, const QString &source, QList<QQmlError> *reportedErrors = 0);
static ReturnedValue evaluate(ExecutionEngine *engine, const QString &script, Object *scopeObject);
};