#include "qv4arraydata_p.h"
#include "qv4object_p.h"
#include "qv4functionobject_p.h"
+#include "qv4mm_p.h"
using namespace QV4;
{
DEFINE_MANAGED_VTABLE_INT(SimpleArrayData),
SimpleArrayData::Simple,
- SimpleArrayData::reserve,
+ SimpleArrayData::reallocate,
SimpleArrayData::get,
SimpleArrayData::put,
SimpleArrayData::putArray,
{
DEFINE_MANAGED_VTABLE_INT(SparseArrayData),
ArrayData::Sparse,
- SparseArrayData::reserve,
+ SparseArrayData::reallocate,
SparseArrayData::get,
SparseArrayData::put,
SparseArrayData::putArray,
};
-void SimpleArrayData::getHeadRoom(ArrayData *d)
+void ArrayData::realloc(Object *o, Type newType, uint offset, uint alloc, bool enforceAttributes)
{
- SimpleArrayData *dd = static_cast<SimpleArrayData *>(d);
- Q_ASSERT(dd);
- Q_ASSERT(!dd->offset);
- dd->offset = qMax(dd->len >> 2, (uint)16);
- SafeValue *newArray = new SafeValue[dd->offset + dd->alloc];
- memcpy(newArray + dd->offset, dd->data, dd->len*sizeof(SafeValue));
- delete [] dd->data;
- dd->data = newArray + dd->offset;
- if (dd->attrs) {
- PropertyAttributes *newAttrs = new PropertyAttributes[dd->offset + dd->alloc];
- memcpy(newAttrs + dd->offset, dd->attrs, dd->len*sizeof(PropertyAttributes));
- delete [] dd->attrs;
- dd->attrs = newAttrs + dd->offset;
+ ArrayData *d = o->arrayData;
+
+ uint oldAlloc = 0;
+ uint toCopy = 0;
+ if (alloc < 8)
+ alloc = 8;
+
+ if (d) {
+ bool hasAttrs = d->attrs;
+ enforceAttributes |= hasAttrs;
+
+ if (!offset && alloc <= d->alloc && newType == d->type && hasAttrs == enforceAttributes)
+ return;
+
+ oldAlloc = d->alloc;
+ if (d->type < Sparse) {
+ offset = qMax(offset, static_cast<SimpleArrayData *>(d)->offset);
+ toCopy = static_cast<SimpleArrayData *>(d)->len;
+ } else {
+ Q_ASSERT(!offset);
+ toCopy = d->alloc;
+ newType = Sparse;
+ }
+ }
+ if (enforceAttributes && newType == Simple)
+ newType = Complex;
+
+ alloc = qMax(alloc, 2*oldAlloc) + offset;
+ size_t size = alloc*sizeof(SafeValue);
+ if (enforceAttributes)
+ size += alloc*sizeof(PropertyAttributes);
+
+ if (newType < Sparse) {
+ size += sizeof(SimpleArrayData);
+ SimpleArrayData *newData = static_cast<SimpleArrayData *>(o->engine()->memoryManager->allocManaged(size));
+ new (newData) SimpleArrayData(o->engine());
+ newData->alloc = alloc - offset;
+ newData->type = newType;
+ newData->data = reinterpret_cast<SafeValue *>(newData + 1) + offset;
+ newData->attrs = enforceAttributes ? reinterpret_cast<PropertyAttributes *>(newData->data + alloc) + offset : 0;
+ newData->offset = offset;
+ newData->len = d ? static_cast<SimpleArrayData *>(d)->len : 0;
+ o->arrayData = newData;
+ } else {
+ size += sizeof(SparseArrayData);
+ SparseArrayData *newData = static_cast<SparseArrayData *>(o->engine()->memoryManager->allocManaged(size));
+ new (newData) SparseArrayData(o->engine());
+ newData->alloc = alloc;
+ newData->type = newType;
+ newData->data = reinterpret_cast<SafeValue *>(newData + 1);
+ newData->attrs = enforceAttributes ? reinterpret_cast<PropertyAttributes *>(newData->data + alloc) : 0;
+ o->arrayData = newData;
}
-}
-void SimpleArrayData::reserve(ArrayData *d, uint n)
-{
- SimpleArrayData *dd = static_cast<SimpleArrayData *>(d);
- if (n < 8)
- n = 8;
- if (n <= dd->alloc)
+ if (d) {
+ memcpy(o->arrayData->data, d->data, sizeof(SafeValue)*toCopy);
+ if (enforceAttributes) {
+ if (d->attrs)
+ memcpy(o->arrayData->attrs, d->attrs, sizeof(PropertyAttributes)*toCopy);
+ else
+ for (uint i = 0; i < toCopy; ++i)
+ o->arrayData->attrs[i] = Attr_Data;
+ }
+ }
+
+ if (newType != Sparse)
return;
- dd->alloc = qMax(n, 2*dd->alloc);
- SafeValue *newArrayData = new SafeValue[dd->alloc + dd->offset];
- if (dd->data) {
- memcpy(newArrayData + dd->offset, dd->data, sizeof(SafeValue)*dd->len);
- delete [] (dd->data - dd->offset);
+ SparseArrayData *newData = static_cast<SparseArrayData *>(o->arrayData);
+ if (d && d->type == Sparse) {
+ SparseArrayData *old = static_cast<SparseArrayData *>(d);
+ newData->sparse = old->sparse;
+ old->sparse = 0;
+ newData->freeList = old->freeList;
+ return;
}
- dd->data = newArrayData + dd->offset;
-
- if (dd->attrs) {
- PropertyAttributes *newAttrs = new PropertyAttributes[dd->alloc];
- memcpy(newAttrs, dd->attrs, sizeof(PropertyAttributes)*dd->len);
- delete [] (dd->attrs - dd->offset);
- dd->attrs = newAttrs;
+ newData->sparse = new SparseArray;
+ uint *lastFree = &newData->freeList;
+ for (uint i = 0; i < toCopy; ++i) {
+ if (!newData->data[i].isEmpty()) {
+ SparseArrayNode *n = newData->sparse->insert(i);
+ n->value = i;
+ } else {
+ *lastFree = i;
+ newData->data[i].tag = Value::Empty_Type;
+ lastFree = &newData->data[i].uint_32;
+ }
+ }
+ for (uint i = toCopy; i < newData->alloc; ++i) {
+ *lastFree = i;
+ newData->data[i].tag = Value::Empty_Type;
+ lastFree = &newData->data[i].uint_32;
}
+ *lastFree = newData->alloc;
+
+ // ### Could explicitly free the old data
}
-void ArrayData::ensureAttributes()
+
+void SimpleArrayData::getHeadRoom(Object *o)
{
- if (attrs)
+ 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);
+ return o->arrayData;
+}
+
+void ArrayData::ensureAttributes(Object *o)
+{
+ if (o->arrayData && o->arrayData->attrs)
return;
- uint off = 0;
- if (type == Simple) {
- type = Complex;
- off = static_cast<SimpleArrayData *>(this)->offset;
- }
- attrs = new PropertyAttributes[alloc + off];
- attrs += off;
- for (uint i = 0; i < alloc; ++i)
- attrs[i] = Attr_Data;
+ ArrayData::realloc(o, Simple, 0, 0, true);
}
-void SimpleArrayData::destroy(Managed *d)
+void SimpleArrayData::destroy(Managed *)
{
- SimpleArrayData *dd = static_cast<SimpleArrayData *>(d);
- delete [] (dd->data - dd->offset);
- if (dd->attrs)
- delete [] (dd->attrs - dd->offset);
}
void SimpleArrayData::markObjects(Managed *d, ExecutionEngine *e)
SimpleArrayData *dd = static_cast<SimpleArrayData *>(o->arrayData);
Q_ASSERT(!dd->attrs);
for (int i = n - 1; i >= 0; --i) {
- if (!dd->offset)
- getHeadRoom(dd);
+ if (!dd->offset) {
+ getHeadRoom(o);
+ dd = static_cast<SimpleArrayData *>(o->arrayData);
+ }
+
--dd->offset;
--dd->data;
bool SimpleArrayData::putArray(Object *o, uint index, SafeValue *values, uint n)
{
SimpleArrayData *dd = static_cast<SimpleArrayData *>(o->arrayData);
- if (index + n > dd->alloc)
- reserve(dd, index + n + 1);
+ if (index + n > dd->alloc) {
+ reallocate(o, index + n + 1, false);
+ dd = static_cast<SimpleArrayData *>(o->arrayData);
+ }
for (uint i = dd->len; i < index; ++i)
dd->data[i] = Primitive::emptyValue();
for (uint i = 0; i < n; ++i)
{
SparseArrayData *dd = static_cast<SparseArrayData *>(d);
delete dd->sparse;
- delete [] dd->data;
- if (dd->attrs)
- delete [] dd->attrs;
}
void SparseArrayData::markObjects(Managed *d, ExecutionEngine *e)
dd->data[i].mark(e);
}
-void SparseArrayData::reserve(ArrayData *d, uint n)
+ArrayData *SparseArrayData::reallocate(Object *o, uint n, bool enforceAttributes)
{
- if (n < 8)
- n = 8;
- if (n <= d->alloc)
- return;
-
- SparseArrayData *dd = static_cast<SparseArrayData *>(d);
- uint oldAlloc = dd->alloc;
- dd->alloc = qMax(n, 2*dd->alloc);
- SafeValue *newArrayData = new SafeValue[dd->alloc];
- if (dd->data) {
- memcpy(newArrayData, dd->data, sizeof(SafeValue)*oldAlloc);
- delete [] dd->data;
- }
- dd->data = newArrayData;
- if (dd->attrs) {
- PropertyAttributes *newAttrs = new PropertyAttributes[dd->alloc];
- memcpy(newAttrs, dd->attrs, sizeof(PropertyAttributes)*oldAlloc);
- delete [] dd->attrs;
- dd->attrs = newAttrs;
- }
- for (uint i = oldAlloc; i < dd->alloc; ++i)
- dd->data[i] = Primitive::fromInt32(i + 1);
+ realloc(o, Sparse, 0, n, enforceAttributes);
+ return o->arrayData;
}
// double slots are required for accessor properties
-uint SparseArrayData::allocate(ArrayData *d, bool doubleSlot)
+uint SparseArrayData::allocate(Object *o, bool doubleSlot)
{
- Q_ASSERT(d->type == ArrayData::Sparse);
- SparseArrayData *dd = static_cast<SparseArrayData *>(d);
+ Q_ASSERT(o->arrayData->type == ArrayData::Sparse);
+ SparseArrayData *dd = static_cast<SparseArrayData *>(o->arrayData);
if (doubleSlot) {
uint *last = &dd->freeList;
while (1) {
if (*last + 1 >= dd->alloc) {
- reserve(d, d->alloc + 2);
+ reallocate(o, o->arrayData->alloc + 2, true);
+ dd = static_cast<SparseArrayData *>(o->arrayData);
last = &dd->freeList;
}
// found two slots in a row
uint idx = *last;
*last = dd->data[*last + 1].uint_32;
- d->attrs[idx] = Attr_Accessor;
+ o->arrayData->attrs[idx] = Attr_Accessor;
return idx;
}
last = &dd->data[*last].uint_32;
}
} else {
- if (dd->alloc == dd->freeList)
- reserve(d, d->alloc + 2);
+ if (dd->alloc == dd->freeList) {
+ reallocate(o, o->arrayData->alloc + 2, false);
+ dd = static_cast<SparseArrayData *>(o->arrayData);
+ }
uint idx = dd->freeList;
dd->freeList = dd->data[idx].uint_32;
if (dd->attrs)
SparseArrayNode *n = static_cast<SparseArrayData *>(o->arrayData)->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->arrayData);
+ n->value = allocate(o);
o->arrayData->data[n->value] = value;
if (o->arrayData->attrs)
o->arrayData->attrs[n->value] = Attr_Data;
{
SparseArrayData *d = static_cast<SparseArrayData *>(o->arrayData);
SparseArrayNode *n = d->sparse->insert(index);
- if (n->value == UINT_MAX)
- n->value = allocate(d, attrs.isAccessor());
+ if (n->value == UINT_MAX) {
+ n->value = allocate(o, attrs.isAccessor());
+ d = static_cast<SparseArrayData *>(o->arrayData);
+ }
else if (attrs.isAccessor() != d->attrs[n->value].isAccessor()) {
// need to convert the slot
free(d, n->value);
- n->value = allocate(d, attrs.isAccessor());
+ n->value = allocate(o, attrs.isAccessor());
}
- d->attrs[n->value] = attrs;
+ o->arrayData->attrs[n->value] = attrs;
}
PropertyAttributes SparseArrayData::attribute(const ArrayData *d, uint index)
{
Q_ASSERT(!o->arrayData->attrs);
for (int i = n - 1; i >= 0; --i) {
- uint idx = allocate(o->arrayData);
+ uint idx = allocate(o);
o->arrayData->data[idx] = values[i];
static_cast<SparseArrayData *>(o->arrayData)->sparse->push_front(idx);
}
o->initSparseArray();
SparseArrayNode *n = static_cast<SparseArrayData *>(o->arrayData)->sparse->insert(index);
if (n->value == UINT_MAX)
- n->value = SparseArrayData::allocate(o->arrayData, isAccessor);
+ n->value = SparseArrayData::allocate(o, isAccessor);
return reinterpret_cast<Property *>(o->arrayData->data + n->value);
}
if (!sparse->sparse->nEntries())
return;
- SimpleArrayData *d = new (context->engine->memoryManager) SimpleArrayData(context->engine);
- thisObject->arrayData = d;
- d->vtable()->reserve(d, sparse->sparse->nEntries());
+ thisObject->arrayData = 0;
+ ArrayData::realloc(thisObject, ArrayData::Simple, 0, sparse->sparse->nEntries(), sparse->attrs ? true : false);
+ SimpleArrayData *d = static_cast<SimpleArrayData *>(thisObject->arrayData);
SparseArrayNode *n = sparse->sparse->begin();
uint i = 0;
if (sparse->attrs) {
- d->ensureAttributes();
while (n != sparse->sparse->end()) {
if (n->value >= len)
break;
{
ManagedVTable managedVTable;
uint type;
- void (*reserve)(ArrayData *d, uint n);
+ ArrayData *(*reallocate)(Object *o, uint n, bool enforceAttributes);
ReturnedValue (*get)(const ArrayData *d, uint index);
bool (*put)(Object *o, uint index, ValueRef value);
bool (*putArray)(Object *o, uint index, SafeValue *values, uint n);
{
ArrayData(InternalClass *ic)
: Managed(ic)
- , alloc(0)
- , type(0)
- , attrs(0)
- , data(0)
{
}
};
uint alloc;
- uint type;
+ Type type;
PropertyAttributes *attrs;
SafeValue *data;
bool hasAttributes() const {
return this && attrs;
}
- void ensureAttributes();
PropertyAttributes attributes(int i) const {
Q_ASSERT(this);
return attrs ? vtable()->attribute(this, i) : Attr_Data;
}
inline Property *getProperty(uint index) const;
+ static void ensureAttributes(Object *o);
+ static void realloc(Object *o, Type newType, uint offset, uint alloc, bool enforceAttributes);
+
static void sort(ExecutionContext *context, ObjectRef thisObject, const ValueRef comparefn, uint dataLen);
static uint append(Object *obj, const ArrayObject *otherObj, uint n);
static Property *insert(Object *o, uint index, bool isAccessor = false);
SimpleArrayData(ExecutionEngine *engine)
: ArrayData(engine->emptyClass)
- , len(0)
- , offset(0)
{ setVTable(staticVTable()); }
uint len;
uint offset;
- static void getHeadRoom(ArrayData *d);
- static void reserve(ArrayData *d, uint n);
+ static void getHeadRoom(Object *o);
+ static ArrayData *reallocate(Object *o, uint n, bool enforceAttributes);
static void destroy(Managed *d);
static void markObjects(Managed *d, ExecutionEngine *e);
SparseArrayData(ExecutionEngine *engine)
: ArrayData(engine->emptyClass)
- , freeList(0)
- , sparse(0)
{ setVTable(staticVTable()); }
uint freeList;
SparseArray *sparse;
- static uint allocate(ArrayData *d, bool doubleSlot = false);
+ static uint allocate(Object *o, bool doubleSlot = false);
static void free(ArrayData *d, uint idx);
static void destroy(Managed *d);
static void markObjects(Managed *d, ExecutionEngine *e);
- static void reserve(ArrayData *d, uint n);
+ static ArrayData *reallocate(Object *o, uint n, bool enforceAttributes);
static ReturnedValue get(const ArrayData *d, uint index);
static bool put(Object *o, uint index, ValueRef value);
static bool putArray(Object *o, uint index, SafeValue *values, uint n);
}
} else {
Q_ASSERT(!arrayData && other->arrayData);
+ ArrayData::realloc(this, other->arrayData->type, 0, other->arrayData->alloc, other->arrayData->attrs);
if (other->arrayType() == ArrayData::Sparse) {
SparseArrayData *od = static_cast<SparseArrayData *>(other->arrayData);
- SparseArrayData *dd = new (engine()->memoryManager) SparseArrayData(engine());
- dd->type = ArrayData::Sparse;
+ SparseArrayData *dd = static_cast<SparseArrayData *>(arrayData);
dd->sparse = new SparseArray(*od->sparse);
dd->freeList = od->freeList;
- arrayData = dd;
- }
- arrayReserve(other->arrayData->alloc);
- if (other->arrayType() != ArrayData::Sparse) {
+ } else {
SimpleArrayData *d = static_cast<SimpleArrayData *>(arrayData);
d->len = static_cast<SimpleArrayData *>(other->arrayData)->len;
d->offset = 0;
}
memcpy(arrayData->data, other->arrayData->data, arrayData->alloc*sizeof(SafeValue));
-
}
setArrayLengthUnchecked(other->getLength());
}
if (arrayType() == ArrayData::Sparse)
return;
- SparseArrayData *data = new (engine()->memoryManager) SparseArrayData(engine());
- data->type = ArrayData::Sparse;
- data->sparse = new SparseArray;
- if (!arrayData) {
- arrayData = data;
- return;
- }
- SimpleArrayData *simple = static_cast<SimpleArrayData *>(arrayData);
-
- uint oldOffset = simple->offset;
- uint length = simple->ArrayData::length();
- data->data = simple->data - simple->offset;
- data->attrs = simple->attrs;
- data->alloc = simple->alloc;
- simple->data = 0;
- simple->attrs = 0;
- // ### explicitly free old data? delete simple;
- arrayData = data;
-
- uint *lastFree = &data->freeList;
- for (uint i = 0; i < oldOffset; ++i) {
- *lastFree = i;
- data->data[i].tag = Value::Empty_Type;
- lastFree = &data->data[i].uint_32;
- }
- for (uint i = 0; i < length; ++i) {
- if (!data->data[i + oldOffset].isEmpty()) {
- SparseArrayNode *n = data->sparse->insert(i);
- n->value = i + oldOffset;
- } else {
- *lastFree = i + oldOffset;
- data->data[i + oldOffset].tag = Value::Empty_Type;
- lastFree = &data->data[i + oldOffset].uint_32;
- }
- }
- for (uint i = length + oldOffset; i < data->alloc; ++i) {
- *lastFree = i;
- data->data[i].tag = Value::Empty_Type;
- lastFree = &data->data[i].uint_32;
- }
- *lastFree = data->alloc;
+ ArrayData::realloc(this, ArrayData::Sparse, 0, 0, false);
}