Unify mark handling for MemberData and ArrayData
Introduce a ValueArray class, that defines an array of Values at the end of a Heap Object. Change-Id: I00efbf6f5839a6687dd5bc5fc037ec8f06e0936e Reviewed-by: Simon Hausmann <simon.hausmann@qt.io>
This commit is contained in:
parent
58b882ad42
commit
10c1e40533
|
@ -91,7 +91,7 @@ void ArgumentsObject::fullyCreate()
|
|||
if (numAccessors) {
|
||||
d()->mappedArguments = md->allocate(engine(), numAccessors);
|
||||
for (uint i = 0; i < numAccessors; ++i) {
|
||||
d()->mappedArguments->data[i] = context()->callData->args[i];
|
||||
d()->mappedArguments->values[i] = context()->callData->args[i];
|
||||
arraySet(i, context()->engine->argumentsAccessors + i, Attr_Accessor);
|
||||
}
|
||||
}
|
||||
|
@ -122,7 +122,7 @@ bool ArgumentsObject::defineOwnProperty(ExecutionEngine *engine, uint index, con
|
|||
map->copy(pd, mapAttrs);
|
||||
setArrayAttributes(index, Attr_Data);
|
||||
pd = arrayData()->getProperty(index);
|
||||
pd->value = d()->mappedArguments->data[index];
|
||||
pd->value = d()->mappedArguments->values[index];
|
||||
}
|
||||
|
||||
bool strict = engine->current->strictMode;
|
||||
|
|
|
@ -129,7 +129,7 @@ void ArrayData::realloc(Object *o, Type newType, uint requested, bool enforceAtt
|
|||
|
||||
if (d->type() < Heap::ArrayData::Sparse) {
|
||||
offset = d->d()->offset;
|
||||
toCopy = d->d()->len;
|
||||
toCopy = d->d()->values.size;
|
||||
} else {
|
||||
toCopy = d->alloc();
|
||||
}
|
||||
|
@ -150,7 +150,7 @@ void ArrayData::realloc(Object *o, Type newType, uint requested, bool enforceAtt
|
|||
Heap::SimpleArrayData *n = scope.engine->memoryManager->allocManaged<SimpleArrayData>(size);
|
||||
n->init();
|
||||
n->offset = 0;
|
||||
n->len = d ? d->d()->len : 0;
|
||||
n->values.size = d ? d->d()->values.size : 0;
|
||||
newData = n;
|
||||
} else {
|
||||
Heap::SparseArrayData *n = scope.engine->memoryManager->allocManaged<SparseArrayData>(size);
|
||||
|
@ -159,7 +159,7 @@ void ArrayData::realloc(Object *o, Type newType, uint requested, bool enforceAtt
|
|||
}
|
||||
newData->setAlloc(alloc);
|
||||
newData->setType(newType);
|
||||
newData->setAttrs(enforceAttributes ? reinterpret_cast<PropertyAttributes *>(newData->d()->arrayData + alloc) : 0);
|
||||
newData->setAttrs(enforceAttributes ? reinterpret_cast<PropertyAttributes *>(newData->d()->values.v + alloc) : 0);
|
||||
o->setArrayData(newData);
|
||||
|
||||
if (d) {
|
||||
|
@ -171,12 +171,12 @@ void ArrayData::realloc(Object *o, Type newType, uint requested, bool enforceAtt
|
|||
newData->attrs()[i] = Attr_Data;
|
||||
}
|
||||
|
||||
if (toCopy > d->d()->alloc - offset) {
|
||||
uint copyFromStart = toCopy - (d->d()->alloc - offset);
|
||||
memcpy(newData->d()->arrayData + toCopy - copyFromStart, d->d()->arrayData, sizeof(Value)*copyFromStart);
|
||||
if (toCopy > d->d()->values.alloc - offset) {
|
||||
uint copyFromStart = toCopy - (d->d()->values.alloc - offset);
|
||||
memcpy(newData->d()->values.v + toCopy - copyFromStart, d->d()->values.v, sizeof(Value)*copyFromStart);
|
||||
toCopy -= copyFromStart;
|
||||
}
|
||||
memcpy(newData->d()->arrayData, d->d()->arrayData + offset, sizeof(Value)*toCopy);
|
||||
memcpy(newData->d()->values.v, d->d()->values.v + offset, sizeof(Value)*toCopy);
|
||||
}
|
||||
|
||||
if (newType != Heap::ArrayData::Sparse)
|
||||
|
@ -196,22 +196,22 @@ void ArrayData::realloc(Object *o, Type newType, uint requested, bool enforceAtt
|
|||
lastFree = &sparse->freeList;
|
||||
storeValue(lastFree, 0);
|
||||
for (uint i = 0; i < toCopy; ++i) {
|
||||
if (!sparse->arrayData[i].isEmpty()) {
|
||||
if (!sparse->values[i].isEmpty()) {
|
||||
SparseArrayNode *n = sparse->sparse->insert(i);
|
||||
n->value = i;
|
||||
} else {
|
||||
storeValue(lastFree, i);
|
||||
sparse->arrayData[i].setEmpty();
|
||||
lastFree = &sparse->arrayData[i].rawValueRef();
|
||||
sparse->values[i].setEmpty();
|
||||
lastFree = &sparse->values[i].rawValueRef();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (toCopy < sparse->alloc) {
|
||||
for (uint i = toCopy; i < sparse->alloc; ++i) {
|
||||
if (toCopy < sparse->values.alloc) {
|
||||
for (uint i = toCopy; i < sparse->values.alloc; ++i) {
|
||||
storeValue(lastFree, i);
|
||||
sparse->arrayData[i].setEmpty();
|
||||
lastFree = &sparse->arrayData[i].rawValueRef();
|
||||
sparse->values[i].setEmpty();
|
||||
lastFree = &sparse->values[i].rawValueRef();
|
||||
}
|
||||
storeValue(lastFree, UINT_MAX);
|
||||
}
|
||||
|
@ -237,7 +237,7 @@ void ArrayData::ensureAttributes(Object *o)
|
|||
ReturnedValue SimpleArrayData::get(const Heap::ArrayData *d, uint index)
|
||||
{
|
||||
const Heap::SimpleArrayData *dd = static_cast<const Heap::SimpleArrayData *>(d);
|
||||
if (index >= dd->len)
|
||||
if (index >= dd->values.size)
|
||||
return Primitive::emptyValue().asReturnedValue();
|
||||
return dd->data(index).asReturnedValue();
|
||||
}
|
||||
|
@ -245,13 +245,13 @@ ReturnedValue SimpleArrayData::get(const Heap::ArrayData *d, uint index)
|
|||
bool SimpleArrayData::put(Object *o, uint index, const Value &value)
|
||||
{
|
||||
Heap::SimpleArrayData *dd = o->d()->arrayData.cast<Heap::SimpleArrayData>();
|
||||
Q_ASSERT(index >= dd->len || !dd->attrs || !dd->attrs[index].isAccessor());
|
||||
Q_ASSERT(index >= dd->values.size || !dd->attrs || !dd->attrs[index].isAccessor());
|
||||
// ### honour attributes
|
||||
dd->data(index) = value;
|
||||
if (index >= dd->len) {
|
||||
if (index >= dd->values.size) {
|
||||
if (dd->attrs)
|
||||
dd->attrs[index] = Attr_Data;
|
||||
dd->len = index + 1;
|
||||
dd->values.size = index + 1;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
@ -259,7 +259,7 @@ bool SimpleArrayData::put(Object *o, uint index, const Value &value)
|
|||
bool SimpleArrayData::del(Object *o, uint index)
|
||||
{
|
||||
Heap::SimpleArrayData *dd = o->d()->arrayData.cast<Heap::SimpleArrayData>();
|
||||
if (index >= dd->len)
|
||||
if (index >= dd->values.size)
|
||||
return true;
|
||||
|
||||
if (!dd->attrs || dd->attrs[index].isConfigurable()) {
|
||||
|
@ -282,8 +282,8 @@ void SimpleArrayData::push_front(Object *o, const Value *values, uint n)
|
|||
{
|
||||
Heap::SimpleArrayData *dd = o->d()->arrayData.cast<Heap::SimpleArrayData>();
|
||||
Q_ASSERT(!dd->attrs);
|
||||
if (dd->len + n > dd->alloc) {
|
||||
realloc(o, Heap::ArrayData::Simple, dd->len + n, false);
|
||||
if (dd->values.size + n > dd->values.alloc) {
|
||||
realloc(o, Heap::ArrayData::Simple, dd->values.size + n, false);
|
||||
Q_ASSERT(o->d()->arrayData->type == Heap::ArrayData::Simple);
|
||||
dd = o->d()->arrayData.cast<Heap::SimpleArrayData>();
|
||||
}
|
||||
|
@ -291,10 +291,10 @@ void SimpleArrayData::push_front(Object *o, const Value *values, uint n)
|
|||
dd->offset -= n; // there is enough space left in front
|
||||
} else {
|
||||
// we need to wrap around, so:
|
||||
dd->offset = dd->alloc - // start at the back, but subtract:
|
||||
dd->offset = dd->values.alloc - // start at the back, but subtract:
|
||||
(n - dd->offset); // the number of items we can put in the free space at the start of the allocated array
|
||||
}
|
||||
dd->len += n;
|
||||
dd->values.size += n;
|
||||
for (uint i = 0; i < n; ++i)
|
||||
dd->data(i) = values[i].asReturnedValue();
|
||||
}
|
||||
|
@ -303,58 +303,58 @@ ReturnedValue SimpleArrayData::pop_front(Object *o)
|
|||
{
|
||||
Heap::SimpleArrayData *dd = o->d()->arrayData.cast<Heap::SimpleArrayData>();
|
||||
Q_ASSERT(!dd->attrs);
|
||||
if (!dd->len)
|
||||
if (!dd->values.size)
|
||||
return Encode::undefined();
|
||||
|
||||
ReturnedValue v = dd->data(0).isEmpty() ? Encode::undefined() : dd->data(0).asReturnedValue();
|
||||
dd->offset = (dd->offset + 1) % dd->alloc;
|
||||
--dd->len;
|
||||
dd->offset = (dd->offset + 1) % dd->values.alloc;
|
||||
--dd->values.size;
|
||||
return v;
|
||||
}
|
||||
|
||||
uint SimpleArrayData::truncate(Object *o, uint newLen)
|
||||
{
|
||||
Heap::SimpleArrayData *dd = o->d()->arrayData.cast<Heap::SimpleArrayData>();
|
||||
if (dd->len < newLen)
|
||||
if (dd->values.size < newLen)
|
||||
return newLen;
|
||||
|
||||
if (!dd->attrs) {
|
||||
dd->len = newLen;
|
||||
dd->values.size = 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;
|
||||
while (dd->values.size > newLen) {
|
||||
if (!dd->data(dd->values.size - 1).isEmpty() && !dd->attrs[dd->values.size - 1].isConfigurable())
|
||||
return dd->values.size;
|
||||
--dd->values.size;
|
||||
}
|
||||
return dd->len;
|
||||
return dd->values.size;
|
||||
}
|
||||
|
||||
uint SimpleArrayData::length(const Heap::ArrayData *d)
|
||||
{
|
||||
return d->len;
|
||||
return d->values.size;
|
||||
}
|
||||
|
||||
bool SimpleArrayData::putArray(Object *o, uint index, const Value *values, uint n)
|
||||
{
|
||||
Heap::SimpleArrayData *dd = o->d()->arrayData.cast<Heap::SimpleArrayData>();
|
||||
if (index + n > dd->alloc) {
|
||||
if (index + n > dd->values.alloc) {
|
||||
reallocate(o, index + n + 1, false);
|
||||
dd = o->d()->arrayData.cast<Heap::SimpleArrayData>();
|
||||
}
|
||||
for (uint i = dd->len; i < index; ++i)
|
||||
for (uint i = dd->values.size; i < index; ++i)
|
||||
dd->data(i) = Primitive::emptyValue();
|
||||
for (uint i = 0; i < n; ++i)
|
||||
dd->data(index + i) = values[i];
|
||||
dd->len = qMax(dd->len, index + n);
|
||||
dd->values.size = qMax(dd->values.size, index + n);
|
||||
return true;
|
||||
}
|
||||
|
||||
void SparseArrayData::free(Heap::ArrayData *d, uint idx)
|
||||
{
|
||||
Q_ASSERT(d && d->type == Heap::ArrayData::Sparse);
|
||||
Value *v = d->arrayData + idx;
|
||||
Value *v = d->values.v + idx;
|
||||
if (d->attrs && d->attrs[idx].isAccessor()) {
|
||||
// double slot, free both. Order is important, so we have a double slot for allocation again afterwards.
|
||||
v[1].setEmpty(Value::fromReturnedValue(d->freeList).emptyValue());
|
||||
|
@ -382,32 +382,32 @@ uint SparseArrayData::allocate(Object *o, bool doubleSlot)
|
|||
ReturnedValue *last = &dd->freeList;
|
||||
while (1) {
|
||||
if (Value::fromReturnedValue(*last).value() == UINT_MAX) {
|
||||
reallocate(o, dd->alloc + 2, true);
|
||||
reallocate(o, dd->values.alloc + 2, true);
|
||||
dd = o->d()->arrayData.cast<Heap::SimpleArrayData>();
|
||||
last = &dd->freeList;
|
||||
Q_ASSERT(Value::fromReturnedValue(*last).value() != UINT_MAX);
|
||||
}
|
||||
|
||||
Q_ASSERT(dd->arrayData[Value::fromReturnedValue(*last).value()].value() != Value::fromReturnedValue(*last).value());
|
||||
if (dd->arrayData[Value::fromReturnedValue(*last).value()].value() == (Value::fromReturnedValue(*last).value() + 1)) {
|
||||
Q_ASSERT(dd->values[Value::fromReturnedValue(*last).value()].value() != Value::fromReturnedValue(*last).value());
|
||||
if (dd->values[Value::fromReturnedValue(*last).value()].value() == (Value::fromReturnedValue(*last).value() + 1)) {
|
||||
// found two slots in a row
|
||||
uint idx = Value::fromReturnedValue(*last).emptyValue();
|
||||
Value lastV = Value::fromReturnedValue(*last);
|
||||
lastV.setEmpty(dd->arrayData[lastV.emptyValue() + 1].value());
|
||||
lastV.setEmpty(dd->values[lastV.emptyValue() + 1].value());
|
||||
*last = lastV.rawValue();
|
||||
dd->attrs[idx] = Attr_Accessor;
|
||||
return idx;
|
||||
}
|
||||
last = &dd->arrayData[Value::fromReturnedValue(*last).value()].rawValueRef();
|
||||
last = &dd->values[Value::fromReturnedValue(*last).value()].rawValueRef();
|
||||
}
|
||||
} else {
|
||||
if (Value::fromReturnedValue(dd->freeList).value() == UINT_MAX) {
|
||||
reallocate(o, dd->alloc + 1, false);
|
||||
reallocate(o, dd->values.alloc + 1, false);
|
||||
dd = o->d()->arrayData.cast<Heap::SimpleArrayData>();
|
||||
}
|
||||
uint idx = Value::fromReturnedValue(dd->freeList).value();
|
||||
Q_ASSERT(idx != UINT_MAX);
|
||||
dd->freeList = dd->arrayData[idx].asReturnedValue();
|
||||
dd->freeList = dd->values[idx].asReturnedValue();
|
||||
Q_ASSERT(Value::fromReturnedValue(dd->freeList).isEmpty());
|
||||
if (dd->attrs)
|
||||
dd->attrs[idx] = Attr_Data;
|
||||
|
@ -421,7 +421,7 @@ ReturnedValue SparseArrayData::get(const Heap::ArrayData *d, uint index)
|
|||
index = s->mappedIndex(index);
|
||||
if (index == UINT_MAX)
|
||||
return Primitive::emptyValue().asReturnedValue();
|
||||
return s->arrayData[index].asReturnedValue();
|
||||
return s->values[index].asReturnedValue();
|
||||
}
|
||||
|
||||
bool SparseArrayData::put(Object *o, uint index, const Value &value)
|
||||
|
@ -435,7 +435,7 @@ bool SparseArrayData::put(Object *o, uint index, const Value &value)
|
|||
if (n->value == UINT_MAX)
|
||||
n->value = allocate(o);
|
||||
s = o->d()->arrayData.cast<Heap::SparseArrayData>();
|
||||
s->arrayData[n->value] = value;
|
||||
s->values[n->value] = value;
|
||||
if (s->attrs)
|
||||
s->attrs[n->value] = Attr_Data;
|
||||
return true;
|
||||
|
@ -450,7 +450,7 @@ bool SparseArrayData::del(Object *o, uint index)
|
|||
return true;
|
||||
|
||||
uint pidx = n->value;
|
||||
Q_ASSERT(!dd->arrayData[pidx].isEmpty());
|
||||
Q_ASSERT(!dd->values[pidx].isEmpty());
|
||||
|
||||
bool isAccessor = false;
|
||||
if (dd->attrs) {
|
||||
|
@ -463,11 +463,11 @@ bool SparseArrayData::del(Object *o, uint index)
|
|||
|
||||
if (isAccessor) {
|
||||
// free up both indices
|
||||
dd->arrayData[pidx + 1].setEmpty(Value::fromReturnedValue(dd->freeList).emptyValue());
|
||||
dd->arrayData[pidx].setEmpty(pidx + 1);
|
||||
dd->values[pidx + 1].setEmpty(Value::fromReturnedValue(dd->freeList).emptyValue());
|
||||
dd->values[pidx].setEmpty(pidx + 1);
|
||||
} else {
|
||||
Q_ASSERT(dd->type == Heap::ArrayData::Sparse);
|
||||
dd->arrayData[pidx].setEmpty(Value::fromReturnedValue(dd->freeList).emptyValue());
|
||||
dd->values[pidx].setEmpty(Value::fromReturnedValue(dd->freeList).emptyValue());
|
||||
}
|
||||
|
||||
dd->freeList = Primitive::emptyValue(pidx).asReturnedValue();
|
||||
|
@ -496,10 +496,10 @@ void SparseArrayData::push_front(Object *o, const Value *values, uint n)
|
|||
{
|
||||
Heap::SparseArrayData *d = o->d()->arrayData.cast<Heap::SparseArrayData>();
|
||||
Q_ASSERT(!d->attrs);
|
||||
for (int i = n - 1; i >= 0; --i) {
|
||||
for (int i = static_cast<int>(n) - 1; i >= 0; --i) {
|
||||
uint idx = allocate(o);
|
||||
d = o->d()->arrayData.cast<Heap::SparseArrayData>();
|
||||
d->arrayData[idx] = values[i];
|
||||
d->values[idx] = values[i];
|
||||
d->sparse->push_front(idx);
|
||||
}
|
||||
}
|
||||
|
@ -511,7 +511,7 @@ ReturnedValue SparseArrayData::pop_front(Object *o)
|
|||
uint idx = d->sparse->pop_front();
|
||||
ReturnedValue v;
|
||||
if (idx != UINT_MAX) {
|
||||
v = d->arrayData[idx].asReturnedValue();
|
||||
v = d->values[idx].asReturnedValue();
|
||||
free(o->arrayData(), idx);
|
||||
} else {
|
||||
v = Encode::undefined();
|
||||
|
@ -589,24 +589,24 @@ uint ArrayData::append(Object *obj, ArrayObject *otherObj, uint n)
|
|||
ScopedValue v(scope);
|
||||
for (const SparseArrayNode *it = os->sparse->begin();
|
||||
it != os->sparse->end(); it = it->nextNode()) {
|
||||
v = otherObj->getValue(os->arrayData[it->value], other->d()->attrs[it->value]);
|
||||
v = otherObj->getValue(os->values[it->value], other->d()->attrs[it->value]);
|
||||
obj->arraySet(oldSize + it->key(), v);
|
||||
}
|
||||
} else {
|
||||
for (const SparseArrayNode *it = other->d()->sparse->begin();
|
||||
it != os->sparse->end(); it = it->nextNode())
|
||||
obj->arraySet(oldSize + it->key(), os->arrayData[it->value]);
|
||||
obj->arraySet(oldSize + it->key(), os->values[it->value]);
|
||||
}
|
||||
} else {
|
||||
Heap::SimpleArrayData *os = static_cast<Heap::SimpleArrayData *>(other->d());
|
||||
uint toCopy = n;
|
||||
uint chunk = toCopy;
|
||||
if (chunk > os->alloc - os->offset)
|
||||
chunk -= os->alloc - os->offset;
|
||||
obj->arrayPut(oldSize, os->arrayData + os->offset, chunk);
|
||||
if (chunk > os->values.alloc - os->offset)
|
||||
chunk -= os->values.alloc - os->offset;
|
||||
obj->arrayPut(oldSize, os->values.v + os->offset, chunk);
|
||||
toCopy -= chunk;
|
||||
if (toCopy)
|
||||
obj->arrayPut(oldSize + chunk, os->arrayData, toCopy);
|
||||
obj->arrayPut(oldSize + chunk, os->values.v, toCopy);
|
||||
}
|
||||
|
||||
return oldSize + n;
|
||||
|
@ -616,18 +616,18 @@ void ArrayData::insert(Object *o, uint index, const Value *v, bool isAccessor)
|
|||
{
|
||||
if (!isAccessor && o->d()->arrayData->type != Heap::ArrayData::Sparse) {
|
||||
Heap::SimpleArrayData *d = o->d()->arrayData.cast<Heap::SimpleArrayData>();
|
||||
if (index < 0x1000 || index < d->len + (d->len >> 2)) {
|
||||
if (index >= d->alloc) {
|
||||
if (index < 0x1000 || index < d->values.size + (d->values.size >> 2)) {
|
||||
if (index >= d->values.alloc) {
|
||||
o->arrayReserve(index + 1);
|
||||
d = o->d()->arrayData.cast<Heap::SimpleArrayData>();
|
||||
}
|
||||
if (index >= d->len) {
|
||||
if (index >= d->values.size) {
|
||||
// mark possible hole in the array
|
||||
for (uint i = d->len; i < index; ++i)
|
||||
for (uint i = d->values.size; i < index; ++i)
|
||||
d->data(i) = Primitive::emptyValue();
|
||||
d->len = index + 1;
|
||||
d->values.size = index + 1;
|
||||
}
|
||||
d->arrayData[d->mappedIndex(index)] = *v;
|
||||
d->values[d->mappedIndex(index)] = *v;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
@ -638,9 +638,9 @@ void ArrayData::insert(Object *o, uint index, const Value *v, bool isAccessor)
|
|||
if (n->value == UINT_MAX)
|
||||
n->value = SparseArrayData::allocate(o, isAccessor);
|
||||
s = o->d()->arrayData.cast<Heap::SparseArrayData>();
|
||||
s->arrayData[n->value] = *v;
|
||||
s->values[n->value] = *v;
|
||||
if (isAccessor)
|
||||
s->arrayData[n->value + Object::SetterOffset] = v[Object::SetterOffset];
|
||||
s->values[n->value + Object::SetterOffset] = v[Object::SetterOffset];
|
||||
}
|
||||
|
||||
|
||||
|
@ -792,7 +792,7 @@ void ArrayData::sort(ExecutionEngine *engine, Object *thisObject, const Value &c
|
|||
++i;
|
||||
}
|
||||
}
|
||||
d->len = i;
|
||||
d->values.size = i;
|
||||
if (len > i)
|
||||
len = i;
|
||||
if (n != sparse->sparse()->end()) {
|
||||
|
@ -808,8 +808,8 @@ void ArrayData::sort(ExecutionEngine *engine, Object *thisObject, const Value &c
|
|||
}
|
||||
} else {
|
||||
Heap::SimpleArrayData *d = thisObject->d()->arrayData.cast<Heap::SimpleArrayData>();
|
||||
if (len > d->len)
|
||||
len = d->len;
|
||||
if (len > d->values.size)
|
||||
len = d->values.size;
|
||||
|
||||
// sort empty values to the end
|
||||
for (uint i = 0; i < len; i++) {
|
||||
|
@ -830,7 +830,7 @@ void ArrayData::sort(ExecutionEngine *engine, Object *thisObject, const Value &c
|
|||
|
||||
ArrayElementLessThan lessThan(engine, thisObject, comparefn);
|
||||
|
||||
Value *begin = thisObject->arrayData()->arrayData;
|
||||
Value *begin = thisObject->arrayData()->values.v;
|
||||
sortHelper(begin, begin + len, *begin, lessThan);
|
||||
|
||||
#ifdef CHECK_SPARSE_ARRAYS
|
||||
|
|
|
@ -98,21 +98,15 @@ struct ArrayDataData {
|
|||
Custom = 3
|
||||
};
|
||||
|
||||
uint alloc;
|
||||
Type type;
|
||||
PropertyAttributes *attrs;
|
||||
union {
|
||||
uint len;
|
||||
ReturnedValue freeList;
|
||||
};
|
||||
union {
|
||||
uint offset;
|
||||
PropertyAttributes *attrs;
|
||||
ReturnedValue freeList;
|
||||
SparseArray *sparse;
|
||||
};
|
||||
Value arrayData[1];
|
||||
ValueArray values;
|
||||
};
|
||||
static Q_CONSTEXPR quint64 ArrayData_markTable = \
|
||||
(MarkFlagsForType<decltype(ArrayDataData::arrayData)>::markFlags << (offsetof(ArrayDataData, arrayData) >> 2)) \
|
||||
(MarkFlagsForType<decltype(ArrayDataData::values)>::markFlags << (offsetof(ArrayDataData, values) >> 2)) \
|
||||
<< (sizeof(Base) >> 2) | QV4::Heap::Base::markTable;
|
||||
|
||||
struct ArrayData : public Base, ArrayDataData {
|
||||
|
@ -135,7 +129,7 @@ struct ArrayData : public Base, ArrayDataData {
|
|||
return get(i) == Primitive::emptyValue().asReturnedValue();
|
||||
}
|
||||
|
||||
inline ReturnedValue length() const {
|
||||
inline uint length() const {
|
||||
return vtable()->length(this);
|
||||
}
|
||||
|
||||
|
@ -143,17 +137,17 @@ struct ArrayData : public Base, ArrayDataData {
|
|||
V4_ASSERT_IS_TRIVIAL(ArrayData)
|
||||
|
||||
struct SimpleArrayData : public ArrayData {
|
||||
uint mappedIndex(uint index) const { return (index + offset) % alloc; }
|
||||
Value data(uint index) const { return arrayData[mappedIndex(index)]; }
|
||||
Value &data(uint index) { return arrayData[mappedIndex(index)]; }
|
||||
uint mappedIndex(uint index) const { return (index + offset) % values.alloc; }
|
||||
Value data(uint index) const { return values[mappedIndex(index)]; }
|
||||
Value &data(uint index) { return values[mappedIndex(index)]; }
|
||||
|
||||
Property *getProperty(uint index) {
|
||||
if (index >= len)
|
||||
if (index >= values.size)
|
||||
return 0;
|
||||
index = mappedIndex(index);
|
||||
if (arrayData[index].isEmpty())
|
||||
if (values[index].isEmpty())
|
||||
return 0;
|
||||
return reinterpret_cast<Property *>(arrayData + index);
|
||||
return reinterpret_cast<Property *>(values.v + index);
|
||||
}
|
||||
|
||||
PropertyAttributes attributes(uint i) const {
|
||||
|
@ -179,7 +173,7 @@ struct SparseArrayData : public ArrayData {
|
|||
SparseArrayNode *n = sparse->findNode(index);
|
||||
if (!n)
|
||||
return 0;
|
||||
return reinterpret_cast<Property *>(arrayData + n->value);
|
||||
return reinterpret_cast<Property *>(values.v + n->value);
|
||||
}
|
||||
|
||||
PropertyAttributes attributes(uint i) const {
|
||||
|
@ -200,15 +194,15 @@ struct Q_QML_EXPORT ArrayData : public Managed
|
|||
IsArrayData = true
|
||||
};
|
||||
|
||||
uint alloc() const { return d()->alloc; }
|
||||
uint &alloc() { return d()->alloc; }
|
||||
void setAlloc(uint a) { d()->alloc = a; }
|
||||
uint alloc() const { return d()->values.alloc; }
|
||||
uint &alloc() { return d()->values.alloc; }
|
||||
void setAlloc(uint a) { d()->values.alloc = a; }
|
||||
Type type() const { return d()->type; }
|
||||
void setType(Type t) { d()->type = t; }
|
||||
PropertyAttributes *attrs() const { return d()->attrs; }
|
||||
void setAttrs(PropertyAttributes *a) { d()->attrs = a; }
|
||||
const Value *arrayData() const { return &d()->arrayData[0]; }
|
||||
Value *arrayData() { return &d()->arrayData[0]; }
|
||||
const Value *arrayData() const { return d()->values.v; }
|
||||
Value *arrayData() { return d()->values.v; }
|
||||
|
||||
const ArrayVTable *vtable() const { return d()->vtable(); }
|
||||
bool isSparse() const { return type() == Heap::ArrayData::Sparse; }
|
||||
|
@ -251,8 +245,8 @@ struct Q_QML_EXPORT SimpleArrayData : public ArrayData
|
|||
Value data(uint index) const { return d()->data(index); }
|
||||
Value &data(uint index) { return d()->data(index); }
|
||||
|
||||
uint &len() { return d()->len; }
|
||||
uint len() const { return d()->len; }
|
||||
uint &len() { return d()->values.size; }
|
||||
uint len() const { return d()->values.size; }
|
||||
|
||||
static Heap::ArrayData *reallocate(Object *o, uint n, bool enforceAttributes);
|
||||
|
||||
|
|
|
@ -690,8 +690,8 @@ void ArrayPrototype::method_indexOf(const BuiltinFunction *, Scope &scope, CallD
|
|||
} else {
|
||||
Q_ASSERT(instance->arrayType() == Heap::ArrayData::Simple || instance->arrayType() == Heap::ArrayData::Complex);
|
||||
Heap::SimpleArrayData *sa = instance->d()->arrayData.cast<Heap::SimpleArrayData>();
|
||||
if (len > sa->len)
|
||||
len = sa->len;
|
||||
if (len > sa->values.size)
|
||||
len = sa->values.size;
|
||||
uint idx = fromIndex;
|
||||
while (idx < len) {
|
||||
value = sa->data(idx);
|
||||
|
|
|
@ -600,11 +600,11 @@ Heap::ArrayObject *ExecutionEngine::newArrayObject(const Value *values, int leng
|
|||
size_t size = sizeof(Heap::ArrayData) + (length-1)*sizeof(Value);
|
||||
Heap::SimpleArrayData *d = scope.engine->memoryManager->allocManaged<SimpleArrayData>(size);
|
||||
d->init();
|
||||
d->alloc = length;
|
||||
d->type = Heap::ArrayData::Simple;
|
||||
d->offset = 0;
|
||||
d->len = length;
|
||||
memcpy(&d->arrayData, values, length*sizeof(Value));
|
||||
d->values.alloc = length;
|
||||
d->values.size = length;
|
||||
memcpy(&d->values.v, values, length*sizeof(Value));
|
||||
a->d()->arrayData = d;
|
||||
a->setArrayLengthUnchecked(length);
|
||||
}
|
||||
|
|
|
@ -302,7 +302,7 @@ void FunctionPrototype::method_apply(const BuiltinFunction *, Scope &scope, Call
|
|||
cData->args[i] = Primitive::undefinedValue();
|
||||
} else if (arr->arrayType() == Heap::ArrayData::Simple && !arr->protoHasArray()) {
|
||||
auto sad = static_cast<Heap::SimpleArrayData *>(arr->arrayData());
|
||||
uint alen = sad ? sad->len : 0;
|
||||
uint alen = sad ? sad->values.size : 0;
|
||||
if (alen > len)
|
||||
alen = len;
|
||||
for (uint i = 0; i < alen; ++i)
|
||||
|
@ -345,7 +345,7 @@ void FunctionPrototype::method_bind(const BuiltinFunction *, Scope &scope, CallD
|
|||
Scoped<MemberData> boundArgs(scope, (Heap::MemberData *)0);
|
||||
if (callData->argc > 1) {
|
||||
boundArgs = MemberData::allocate(scope.engine, callData->argc - 1);
|
||||
boundArgs->d()->size = callData->argc - 1;
|
||||
boundArgs->d()->values.size = callData->argc - 1;
|
||||
memcpy(boundArgs->data(), callData->args + 1, (callData->argc - 1)*sizeof(Value));
|
||||
}
|
||||
|
||||
|
|
|
@ -199,6 +199,7 @@ struct ScriptFunction;
|
|||
struct InternalClass;
|
||||
struct Property;
|
||||
struct Value;
|
||||
struct ValueArray;
|
||||
struct Lookup;
|
||||
struct ArrayData;
|
||||
struct VTable;
|
||||
|
|
|
@ -182,7 +182,7 @@ ReturnedValue Lookup::indexedGetterObjectInt(Lookup *l, const Value &object, con
|
|||
Heap::Object *o = static_cast<Heap::Object *>(b);
|
||||
if (o->arrayData && o->arrayData->type == Heap::ArrayData::Simple) {
|
||||
Heap::SimpleArrayData *s = o->arrayData.cast<Heap::SimpleArrayData>();
|
||||
if (idx < s->len)
|
||||
if (idx < s->values.size)
|
||||
if (!s->data(idx).isEmpty())
|
||||
return s->data(idx).asReturnedValue();
|
||||
}
|
||||
|
@ -217,7 +217,7 @@ void Lookup::indexedSetterFallback(Lookup *l, const Value &object, const Value &
|
|||
if (index.asArrayIndex(idx)) {
|
||||
if (o->d()->arrayData && o->d()->arrayData->type == Heap::ArrayData::Simple) {
|
||||
Heap::SimpleArrayData *s = o->d()->arrayData.cast<Heap::SimpleArrayData>();
|
||||
if (idx < s->len) {
|
||||
if (idx < s->values.size) {
|
||||
s->data(idx) = value;
|
||||
return;
|
||||
}
|
||||
|
@ -239,7 +239,7 @@ void Lookup::indexedSetterObjectInt(Lookup *l, const Value &object, const Value
|
|||
Heap::Object *o = static_cast<Heap::Object *>(b);
|
||||
if (o->arrayData && o->arrayData->type == Heap::ArrayData::Simple) {
|
||||
Heap::SimpleArrayData *s = o->arrayData.cast<Heap::SimpleArrayData>();
|
||||
if (idx < s->len) {
|
||||
if (idx < s->values.size) {
|
||||
s->data(idx) = v;
|
||||
return;
|
||||
}
|
||||
|
|
|
@ -47,15 +47,16 @@ DEFINE_MANAGED_VTABLE(MemberData);
|
|||
|
||||
Heap::MemberData *MemberData::allocate(ExecutionEngine *e, uint n, Heap::MemberData *old)
|
||||
{
|
||||
Q_ASSERT(!old || old->size < n);
|
||||
Q_ASSERT(!old || old->values.size < n);
|
||||
Q_ASSERT(n);
|
||||
|
||||
size_t alloc = MemoryManager::align(sizeof(Heap::MemberData) + (n - 1)*sizeof(Value));
|
||||
Heap::MemberData *m = e->memoryManager->allocManaged<MemberData>(alloc);
|
||||
if (old)
|
||||
memcpy(m, old, sizeof(Heap::MemberData) + (old->size - 1)* sizeof(Value));
|
||||
memcpy(m, old, sizeof(Heap::MemberData) + (old->values.size - 1) * sizeof(Value));
|
||||
else
|
||||
m->init();
|
||||
m->size = static_cast<uint>((alloc - sizeof(Heap::MemberData) + sizeof(Value))/sizeof(Value));
|
||||
m->values.alloc = static_cast<uint>((alloc - sizeof(Heap::MemberData) + sizeof(Value))/sizeof(Value));
|
||||
m->values.size = m->values.alloc;
|
||||
return m;
|
||||
}
|
||||
|
|
|
@ -60,8 +60,7 @@ namespace QV4 {
|
|||
namespace Heap {
|
||||
|
||||
#define MemberDataMembers(class, Member) \
|
||||
Member(class, uint, size) \
|
||||
Member(class, ValueArray, data)
|
||||
Member(class, ValueArray, values)
|
||||
|
||||
DECLARE_HEAP_OBJECT(MemberData, Base) {
|
||||
DECLARE_MARK_TABLE(MemberData);
|
||||
|
@ -74,10 +73,10 @@ struct MemberData : Managed
|
|||
{
|
||||
V4_MANAGED(MemberData, Managed)
|
||||
|
||||
Value &operator[] (uint idx) { return d()->data[idx]; }
|
||||
const Value *data() const { return d()->data; }
|
||||
Value *data() { return d()->data; }
|
||||
inline uint size() const { return d()->size; }
|
||||
Value &operator[] (uint idx) { return d()->values[idx]; }
|
||||
const Value *data() const { return d()->values.v; }
|
||||
Value *data() { return d()->values.v; }
|
||||
inline uint size() const { return d()->values.size; }
|
||||
|
||||
static Heap::MemberData *allocate(QV4::ExecutionEngine *e, uint n, Heap::MemberData *old = 0);
|
||||
};
|
||||
|
|
|
@ -62,7 +62,7 @@ void Object::setInternalClass(InternalClass *ic)
|
|||
{
|
||||
d()->internalClass = ic;
|
||||
bool hasMD = d()->memberData != nullptr;
|
||||
if ((!hasMD && ic->size) || (hasMD && d()->memberData->size < ic->size))
|
||||
if ((!hasMD && ic->size) || (hasMD && d()->memberData->values.size < ic->size))
|
||||
d()->memberData = MemberData::allocate(ic->engine, ic->size, d()->memberData);
|
||||
}
|
||||
|
||||
|
@ -582,7 +582,7 @@ void Object::advanceIterator(Managed *m, ObjectIterator *it, Value *name, uint *
|
|||
int k = it->arrayNode->key();
|
||||
uint pidx = it->arrayNode->value;
|
||||
Heap::SparseArrayData *sa = o->d()->arrayData.cast<Heap::SparseArrayData>();
|
||||
Property *p = reinterpret_cast<Property *>(sa->arrayData + pidx);
|
||||
Property *p = reinterpret_cast<Property *>(sa->values.v + pidx);
|
||||
it->arrayNode = it->arrayNode->nextNode();
|
||||
PropertyAttributes a = sa->attrs ? sa->attrs[pidx] : Attr_Data;
|
||||
if (!(it->flags & ObjectIterator::EnumerableOnly) || a.isEnumerable()) {
|
||||
|
@ -597,7 +597,7 @@ void Object::advanceIterator(Managed *m, ObjectIterator *it, Value *name, uint *
|
|||
it->arrayIndex = UINT_MAX;
|
||||
}
|
||||
// dense arrays
|
||||
while (it->arrayIndex < o->d()->arrayData->len) {
|
||||
while (it->arrayIndex < o->d()->arrayData->values.size) {
|
||||
Heap::SimpleArrayData *sa = o->d()->arrayData.cast<Heap::SimpleArrayData>();
|
||||
Value &val = sa->data(it->arrayIndex);
|
||||
PropertyAttributes a = o->arrayData()->attributes(it->arrayIndex);
|
||||
|
@ -1132,7 +1132,7 @@ void Object::copyArrayData(Object *other)
|
|||
;
|
||||
} else {
|
||||
Q_ASSERT(!arrayData() && other->arrayData());
|
||||
ArrayData::realloc(this, other->d()->arrayData->type, other->d()->arrayData->alloc, false);
|
||||
ArrayData::realloc(this, other->d()->arrayData->type, other->d()->arrayData->values.alloc, false);
|
||||
if (other->arrayType() == Heap::ArrayData::Sparse) {
|
||||
Heap::ArrayData *od = other->d()->arrayData;
|
||||
Heap::ArrayData *dd = d()->arrayData;
|
||||
|
@ -1140,10 +1140,10 @@ void Object::copyArrayData(Object *other)
|
|||
dd->freeList = od->freeList;
|
||||
} else {
|
||||
Heap::ArrayData *dd = d()->arrayData;
|
||||
dd->len = other->d()->arrayData->len;
|
||||
dd->values.size = other->d()->arrayData->values.size;
|
||||
dd->offset = other->d()->arrayData->offset;
|
||||
}
|
||||
memcpy(d()->arrayData->arrayData, other->d()->arrayData->arrayData, other->d()->arrayData->alloc*sizeof(Value));
|
||||
memcpy(d()->arrayData->values.v, other->d()->arrayData->values.v, other->d()->arrayData->values.alloc*sizeof(Value));
|
||||
}
|
||||
setArrayLengthUnchecked(other->getLength());
|
||||
}
|
||||
|
|
|
@ -78,8 +78,8 @@ DECLARE_HEAP_OBJECT(Object, Base) {
|
|||
void init() { Base::init(); }
|
||||
void destroy() { Base::destroy(); }
|
||||
|
||||
const Value *propertyData(uint index) const { return memberData->data + index; }
|
||||
Value *propertyData(uint index) { return memberData->data + index; }
|
||||
const Value *propertyData(uint index) const { return memberData->values.v + index; }
|
||||
Value *propertyData(uint index) { return memberData->values.v + index; }
|
||||
};
|
||||
|
||||
}
|
||||
|
@ -524,7 +524,7 @@ inline void Object::arraySet(uint index, const Property *p, PropertyAttributes a
|
|||
{
|
||||
// ### Clean up
|
||||
arrayCreate();
|
||||
if (attributes.isAccessor() || (index > 0x1000 && index > 2*d()->arrayData->alloc)) {
|
||||
if (attributes.isAccessor() || (index > 0x1000 && index > 2*d()->arrayData->values.alloc)) {
|
||||
initSparseArray();
|
||||
} else {
|
||||
arrayData()->vtable()->reallocate(this, index + 1, false);
|
||||
|
@ -539,7 +539,7 @@ inline void Object::arraySet(uint index, const Property *p, PropertyAttributes a
|
|||
inline void Object::arraySet(uint index, const Value &value)
|
||||
{
|
||||
arrayCreate();
|
||||
if (index > 0x1000 && index > 2*d()->arrayData->alloc) {
|
||||
if (index > 0x1000 && index > 2*d()->arrayData->values.alloc) {
|
||||
initSparseArray();
|
||||
}
|
||||
ArrayData::insert(this, index, &value);
|
||||
|
|
|
@ -295,7 +295,7 @@ void ObjectPrototype::method_seal(const BuiltinFunction *, Scope &scope, CallDat
|
|||
|
||||
if (o->arrayData()) {
|
||||
ArrayData::ensureAttributes(o);
|
||||
for (uint i = 0; i < o->d()->arrayData->alloc; ++i) {
|
||||
for (uint i = 0; i < o->d()->arrayData->values.alloc; ++i) {
|
||||
if (!o->arrayData()->isEmpty(i))
|
||||
o->d()->arrayData->attrs[i].setConfigurable(false);
|
||||
}
|
||||
|
@ -320,7 +320,7 @@ void ObjectPrototype::method_freeze(const BuiltinFunction *, Scope &scope, CallD
|
|||
|
||||
if (o->arrayData()) {
|
||||
ArrayData::ensureAttributes(o);
|
||||
for (uint i = 0; i < o->arrayData()->alloc; ++i) {
|
||||
for (uint i = 0; i < o->arrayData()->values.alloc; ++i) {
|
||||
if (!o->arrayData()->isEmpty(i))
|
||||
o->arrayData()->attrs[i].setConfigurable(false);
|
||||
if (o->arrayData()->attrs[i].isData())
|
||||
|
@ -371,7 +371,7 @@ void ObjectPrototype::method_isSealed(const BuiltinFunction *, Scope &scope, Cal
|
|||
return;
|
||||
}
|
||||
|
||||
for (uint i = 0; i < o->arrayData()->alloc; ++i) {
|
||||
for (uint i = 0; i < o->arrayData()->values.alloc; ++i) {
|
||||
if (!o->arrayData()->isEmpty(i))
|
||||
if (o->arrayData()->attributes(i).isConfigurable()) {
|
||||
scope.result = Encode(false);
|
||||
|
@ -411,7 +411,7 @@ void ObjectPrototype::method_isFrozen(const BuiltinFunction *, Scope &scope, Cal
|
|||
return;
|
||||
}
|
||||
|
||||
for (uint i = 0; i < o->arrayData()->alloc; ++i) {
|
||||
for (uint i = 0; i < o->arrayData()->values.alloc; ++i) {
|
||||
if (!o->arrayData()->isEmpty(i))
|
||||
if (o->arrayData()->attributes(i).isConfigurable() || o->arrayData()->attributes(i).isWritable()) {
|
||||
scope.result = Encode(false);
|
||||
|
|
|
@ -643,7 +643,7 @@ void Runtime::method_setElement(ExecutionEngine *engine, const Value &object, co
|
|||
if (idx < UINT_MAX) {
|
||||
if (o->arrayType() == Heap::ArrayData::Simple) {
|
||||
Heap::SimpleArrayData *s = static_cast<Heap::SimpleArrayData *>(o->arrayData());
|
||||
if (s && idx < s->len && !s->data(idx).isEmpty()) {
|
||||
if (s && idx < s->values.size && !s->data(idx).isEmpty()) {
|
||||
s->data(idx) = value;
|
||||
return;
|
||||
}
|
||||
|
|
|
@ -708,6 +708,20 @@ inline unsigned int Value::toUInt32() const
|
|||
return (unsigned int)toInt32();
|
||||
}
|
||||
|
||||
struct ValueArray {
|
||||
uint size;
|
||||
uint alloc;
|
||||
Value v[1];
|
||||
|
||||
inline Value &operator[] (uint index) {
|
||||
Q_ASSERT(index < alloc);
|
||||
return v[index];
|
||||
}
|
||||
inline const Value &operator[] (uint index) const {
|
||||
Q_ASSERT(index < alloc);
|
||||
return v[index];
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
|
|
|
@ -733,7 +733,8 @@ Heap::Object *MemoryManager::allocObjectWithMemberData(std::size_t size, uint nM
|
|||
memset(m, 0, memberSize);
|
||||
o->memberData = static_cast<Heap::MemberData *>(m);
|
||||
o->memberData->setVtable(MemberData::staticVTable());
|
||||
o->memberData->size = static_cast<uint>((memberSize - sizeof(Heap::MemberData) + sizeof(Value))/sizeof(Value));
|
||||
o->memberData->values.alloc = static_cast<uint>((memberSize - sizeof(Heap::MemberData) + sizeof(Value))/sizeof(Value));
|
||||
o->memberData->values.size = o->memberData->values.alloc;
|
||||
o->memberData->init();
|
||||
// qDebug() << " got" << o->memberData << o->memberData->size;
|
||||
}
|
||||
|
@ -769,17 +770,9 @@ void MemoryManager::drainMarkStack(Value *markBase)
|
|||
case Mark_ValueArray: {
|
||||
Q_ASSERT(m == Mark_ValueArray);
|
||||
// qDebug() << "marking Value Array at offset" << hex << (mem - reinterpret_cast<void **>(h));
|
||||
uint size;
|
||||
Value *v = reinterpret_cast<Value *>(mem);
|
||||
if (h->vtable() == QV4::MemberData::staticVTable()) {
|
||||
size = static_cast<Heap::MemberData *>(h)->size;
|
||||
} else if (h->vtable()->isArrayData) {
|
||||
size = static_cast<Heap::ArrayData *>(h)->alloc;
|
||||
} else {
|
||||
size = 0;
|
||||
Q_ASSERT(false);
|
||||
}
|
||||
const Value *end = v + size;
|
||||
ValueArray *a = reinterpret_cast<ValueArray *>(mem);
|
||||
Value *v = a->v;
|
||||
const Value *end = v + a->alloc;
|
||||
while (v < end) {
|
||||
v->mark(engine);
|
||||
++v;
|
||||
|
|
|
@ -277,8 +277,6 @@ template<>
|
|||
struct MarkFlagsForType<Value> {
|
||||
static const quint64 markFlags = Mark_Value;
|
||||
};
|
||||
|
||||
typedef Value ValueArray[1];
|
||||
template<>
|
||||
struct MarkFlagsForType<ValueArray> {
|
||||
static const quint64 markFlags = Mark_ValueArray;
|
||||
|
|
|
@ -329,7 +329,7 @@ QQmlVMEMetaObject::QQmlVMEMetaObject(QObject *obj,
|
|||
if (size) {
|
||||
QV4::Heap::MemberData *data = QV4::MemberData::allocate(v4, size);
|
||||
propertyAndMethodStorage.set(v4, data);
|
||||
std::fill(data->data, data->data + data->size, QV4::Encode::undefined());
|
||||
std::fill(data->values.v, data->values.v + data->values.size, QV4::Encode::undefined());
|
||||
}
|
||||
|
||||
// Need JS wrapper to ensure properties/methods are marked.
|
||||
|
|
Loading…
Reference in New Issue