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