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:
Lars Knoll 2017-01-27 09:57:00 +01:00
parent 58b882ad42
commit 10c1e40533
18 changed files with 149 additions and 149 deletions

View File

@ -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;

View File

@ -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

View File

@ -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);

View File

@ -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);

View File

@ -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);
}

View File

@ -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));
}

View File

@ -199,6 +199,7 @@ struct ScriptFunction;
struct InternalClass;
struct Property;
struct Value;
struct ValueArray;
struct Lookup;
struct ArrayData;
struct VTable;

View File

@ -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;
}

View File

@ -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;
}

View File

@ -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);
};

View File

@ -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());
}

View File

@ -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);

View File

@ -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);

View File

@ -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;
}

View File

@ -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];
}
};
}

View File

@ -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;

View File

@ -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;

View File

@ -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.