diff options
Diffstat (limited to 'src/qml/jsruntime')
-rw-r--r-- | src/qml/jsruntime/qv4argumentsobject.cpp | 6 | ||||
-rw-r--r-- | src/qml/jsruntime/qv4arraydata.cpp | 269 | ||||
-rw-r--r-- | src/qml/jsruntime/qv4arraydata_p.h | 78 | ||||
-rw-r--r-- | src/qml/jsruntime/qv4arrayobject.cpp | 28 | ||||
-rw-r--r-- | src/qml/jsruntime/qv4dateobject.cpp | 8 | ||||
-rw-r--r-- | src/qml/jsruntime/qv4functionobject.cpp | 14 | ||||
-rw-r--r-- | src/qml/jsruntime/qv4lookup.cpp | 17 | ||||
-rw-r--r-- | src/qml/jsruntime/qv4mm.cpp | 29 | ||||
-rw-r--r-- | src/qml/jsruntime/qv4object.cpp | 43 | ||||
-rw-r--r-- | src/qml/jsruntime/qv4object_p.h | 7 | ||||
-rw-r--r-- | src/qml/jsruntime/qv4objectiterator.cpp | 31 | ||||
-rw-r--r-- | src/qml/jsruntime/qv4objectiterator_p.h | 5 | ||||
-rw-r--r-- | src/qml/jsruntime/qv4objectproto.cpp | 10 | ||||
-rw-r--r-- | src/qml/jsruntime/qv4profiling_p.h | 10 | ||||
-rw-r--r-- | src/qml/jsruntime/qv4runtime.cpp | 6 | ||||
-rw-r--r-- | src/qml/jsruntime/qv4script.cpp | 13 | ||||
-rw-r--r-- | src/qml/jsruntime/qv4script_p.h | 2 |
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); }; |