aboutsummaryrefslogtreecommitdiffstats
path: root/src/qml/jsruntime/qv4object.cpp
diff options
context:
space:
mode:
authorLars Knoll <lars.knoll@digia.com>2013-12-16 09:16:57 +0100
committerThe Qt Project <gerrit-noreply@qt-project.org>2014-01-09 07:47:06 +0100
commit459c9a2a8840995436e610459216957bc7ebd914 (patch)
treeef28df2fdbc62bf551088d13850492d2c6a771b1 /src/qml/jsruntime/qv4object.cpp
parent5cf95512af83fc6a0f70d3493be571accaf50d84 (diff)
Rework array handling for JS objects
Split up ArrayData into two classes, one for regular arrays, one for sparse arrays and cleanly separate the two cases. Only create array data on demand. Change-Id: I9ca8d0b53592174f213ba0f20caf93e77dba690a Reviewed-by: Simon Hausmann <simon.hausmann@digia.com>
Diffstat (limited to 'src/qml/jsruntime/qv4object.cpp')
-rw-r--r--src/qml/jsruntime/qv4object.cpp556
1 files changed, 162 insertions, 394 deletions
diff --git a/src/qml/jsruntime/qv4object.cpp b/src/qml/jsruntime/qv4object.cpp
index fb56d623fd..142eae82fd 100644
--- a/src/qml/jsruntime/qv4object.cpp
+++ b/src/qml/jsruntime/qv4object.cpp
@@ -73,7 +73,6 @@ Object::Object(ExecutionEngine *engine)
: Managed(engine->objectClass)
, memberDataAlloc(InlinePropertySize), memberData(inlineProperties)
{
- flags = SimpleArray;
}
Object::Object(InternalClass *ic)
@@ -81,7 +80,6 @@ Object::Object(InternalClass *ic)
, memberDataAlloc(InlinePropertySize), memberData(inlineProperties)
{
Q_ASSERT(internalClass->vtable && internalClass->vtable != &Managed::static_vtbl);
- flags = SimpleArray;
if (internalClass->size >= memberDataAlloc) {
memberDataAlloc = internalClass->size;
@@ -93,10 +91,8 @@ Object::~Object()
{
if (memberData != inlineProperties)
delete [] memberData;
- delete [] (arrayData.data - (arrayData.sparse ? 0 : arrayData.offset));
- if (arrayData.attributes)
- delete [] (arrayData.attributes - (arrayData.sparse ? 0 : arrayData.offset));
- delete arrayData.sparse;
+ if (arrayData)
+ arrayData->free();
_data = 0;
}
@@ -252,23 +248,8 @@ void Object::markObjects(Managed *that, ExecutionEngine *e)
}
}
}
- if (o->flags & SimpleArray) {
- for (uint i = 0; i < o->arrayData.length; ++i)
- o->arrayData.data[i].value.mark(e);
- return;
- } else {
- for (uint i = 0; i < o->arrayData.length; ++i) {
- const Property &pd = o->arrayData.data[i];
- if (o->arrayData.attributes && o->arrayData.attributes[i].isAccessor()) {
- if (pd.getter())
- pd.getter()->mark(e);
- if (pd.setter())
- pd.setter()->mark(e);
- } else {
- pd.value.mark(e);
- }
- }
- }
+ if (o->arrayData)
+ o->arrayData->markObjects(e);
}
void Object::ensureMemberIndex(uint idx)
@@ -318,12 +299,11 @@ Property *Object::__getOwnProperty__(const StringRef name, PropertyAttributes *a
Property *Object::__getOwnProperty__(uint index, PropertyAttributes *attrs)
{
- uint pidx = propertyIndexFromArrayIndex(index);
- if (pidx < UINT_MAX) {
- Property *p = arrayData.data + pidx;
- if (!p->value.isEmpty() && !(arrayData.attributes && arrayData.attributes[pidx].isGeneric())) {
+ Property *p = arrayData->getProperty(index);
+ if (p) {
+ if (!p->value.isEmpty()) {
if (attrs)
- *attrs = arrayData.attributes ? arrayData.attributes[pidx] : PropertyAttributes(Attr_Data);
+ *attrs = arrayData->attributes(index);
return p;
}
}
@@ -366,12 +346,11 @@ Property *Object::__getPropertyDescriptor__(uint index, PropertyAttributes *attr
{
const Object *o = this;
while (o) {
- uint pidx = o->propertyIndexFromArrayIndex(index);
- if (pidx < UINT_MAX) {
- Property *p = o->arrayData.data + pidx;
+ Property *p = o->arrayData->getProperty(index);
+ if (p) {
if (!p->value.isEmpty()) {
if (attrs)
- *attrs = o->arrayData.attributes ? o->arrayData.attributes[pidx] : PropertyAttributes(Attr_Data);
+ *attrs = o->arrayData->attributes(index);
return p;
}
}
@@ -467,13 +446,9 @@ PropertyAttributes Object::query(const Managed *m, StringRef name)
PropertyAttributes Object::queryIndexed(const Managed *m, uint index)
{
const Object *o = static_cast<const Object *>(m);
- uint pidx = o->propertyIndexFromArrayIndex(index);
- if (pidx < UINT_MAX) {
- if (o->arrayData.attributes)
- return o->arrayData.attributes[pidx];
- if (!o->arrayData.data[pidx].value.isEmpty())
- return Attr_Data;
- }
+ if (o->arrayData->get(index) != Primitive::emptyValue().asReturnedValue())
+ return o->arrayData->attributes(index);
+
if (o->isStringObject()) {
Property *p = static_cast<const StringObject *>(o)->getIndex(index);
if (p)
@@ -574,41 +549,42 @@ Property *Object::advanceIterator(Managed *m, ObjectIterator *it, StringRef name
name = (String *)0;
*index = UINT_MAX;
- if (!it->arrayIndex)
- it->arrayNode = o->sparseArrayBegin();
-
- // sparse arrays
- if (it->arrayNode) {
- while (it->arrayNode != o->sparseArrayEnd()) {
- int k = it->arrayNode->key();
- uint pidx = it->arrayNode->value;
- Property *p = o->arrayData.data + pidx;
- it->arrayNode = it->arrayNode->nextNode();
- PropertyAttributes a = o->arrayData.attributes ? o->arrayData.attributes[pidx] : PropertyAttributes(Attr_Data);
- if (!(it->flags & ObjectIterator::EnumerableOnly) || a.isEnumerable()) {
- it->arrayIndex = k + 1;
- *index = k;
+ if (o->arrayData) {
+ if (!it->arrayIndex)
+ it->arrayNode = o->sparseBegin();
+
+ // sparse arrays
+ if (it->arrayNode) {
+ while (it->arrayNode != o->sparseEnd()) {
+ int k = it->arrayNode->key();
+ uint pidx = it->arrayNode->value;
+ Property *p = o->arrayData->data + pidx;
+ it->arrayNode = it->arrayNode->nextNode();
+ PropertyAttributes a = o->arrayData->attributes(k);
+ if (!(it->flags & ObjectIterator::EnumerableOnly) || a.isEnumerable()) {
+ it->arrayIndex = k + 1;
+ *index = k;
+ if (attrs)
+ *attrs = a;
+ return p;
+ }
+ }
+ it->arrayNode = 0;
+ it->arrayIndex = UINT_MAX;
+ }
+ // dense arrays
+ while (it->arrayIndex < o->arrayData->length()) {
+ Property *p = o->arrayData->data + it->arrayIndex;
+ PropertyAttributes a = o->arrayData->attributes(it->arrayIndex);
+ ++it->arrayIndex;
+ if (!p->value.isEmpty()
+ && (!(it->flags & ObjectIterator::EnumerableOnly) || a.isEnumerable())) {
+ *index = it->arrayIndex - 1;
if (attrs)
*attrs = a;
return p;
}
}
- it->arrayNode = 0;
- it->arrayIndex = UINT_MAX;
- }
- // dense arrays
- while (it->arrayIndex < o->arrayData.length) {
- uint pidx = o->propertyIndexFromArrayIndex(it->arrayIndex);
- Property *p = o->arrayData.data + pidx;
- PropertyAttributes a = o->arrayData.attributes ? o->arrayData.attributes[pidx] : PropertyAttributes(Attr_Data);
- ++it->arrayIndex;
- if (!p->value.isEmpty()
- && (!(it->flags & ObjectIterator::EnumerableOnly) || a.isEnumerable())) {
- *index = it->arrayIndex - 1;
- if (attrs)
- *attrs = a;
- return p;
- }
}
while (it->memberIndex < o->internalClass->size) {
@@ -658,15 +634,14 @@ ReturnedValue Object::internalGet(const StringRef name, bool *hasProperty)
ReturnedValue Object::internalGetIndexed(uint index, bool *hasProperty)
{
Property *pd = 0;
- PropertyAttributes attrs = Attr_Data;
+ PropertyAttributes attrs;
Object *o = this;
while (o) {
- uint pidx = o->propertyIndexFromArrayIndex(index);
- if (pidx < UINT_MAX) {
- if (!o->arrayData.data[pidx].value.isEmpty()) {
- pd = o->arrayData.data + pidx;
- if (o->arrayData.attributes)
- attrs = o->arrayData.attributes[pidx];
+ Property *p = o->arrayData->getProperty(index);
+ if (p) {
+ if (!p->value.isEmpty()) {
+ pd = p;
+ attrs = o->arrayData->attributes(index);
break;
}
}
@@ -788,10 +763,10 @@ void Object::internalPutIndexed(uint index, const ValueRef value)
Property *pd = 0;
PropertyAttributes attrs;
- uint pidx = propertyIndexFromArrayIndex(index);
- if (pidx < UINT_MAX && !arrayData.data[pidx].value.isEmpty()) {
- pd = arrayData.data + pidx;
- attrs = arrayData.attributes ? arrayData.attributes[pidx] : PropertyAttributes(Attr_Data);
+ Property *p = arrayData->getProperty(index);
+ if (p && !p->value.isEmpty()) {
+ pd = p;
+ attrs = arrayData->attributes(index);
}
if (!pd && isStringObject()) {
@@ -883,23 +858,9 @@ bool Object::internalDeleteIndexedProperty(uint index)
if (internalClass->engine->hasException)
return false;
- uint pidx = propertyIndexFromArrayIndex(index);
- if (pidx == UINT_MAX)
- return true;
- if (arrayData.data[pidx].value.isEmpty())
+ if (!arrayData || arrayData->deleteIndex(index))
return true;
- if (!arrayData.attributes || arrayData.attributes[pidx].isConfigurable()) {
- arrayData.data[pidx].value = Primitive::emptyValue();
- if (arrayData.attributes)
- arrayData.attributes[pidx].clear();
- if (arrayData.sparse) {
- arrayData.data[pidx].value.int_32 = arrayData.freeList;
- arrayData.freeList = pidx;
- }
- return true;
- }
-
if (engine()->currentContext()->strictMode)
engine()->currentContext()->throwTypeError();
return false;
@@ -974,7 +935,7 @@ reject:
bool Object::__defineOwnProperty__(ExecutionContext *ctx, uint index, const Property &p, PropertyAttributes attrs)
{
// 15.4.5.1, 4b
- if (isArrayObject() && index >= arrayLength() && !internalClass->propertyData[ArrayObject::LengthPropertyIndex].isWritable())
+ if (isArrayObject() && index >= getLength() && !internalClass->propertyData[ArrayObject::LengthPropertyIndex].isWritable())
goto reject;
if (ArgumentsObject::isNonStrictArgumentsObject(this))
@@ -993,9 +954,9 @@ bool Object::defineOwnProperty2(ExecutionContext *ctx, uint index, const Propert
// Clause 1
{
- uint pidx = propertyIndexFromArrayIndex(index);
- if (pidx < UINT_MAX && !arrayData.data[pidx].value.isEmpty())
- current = arrayData.data + pidx;
+ Property *p = arrayData->getProperty(index);
+ if (p && !p->value.isEmpty())
+ current = p;
if (!current && isStringObject())
current = static_cast<StringObject *>(this)->getIndex(index);
}
@@ -1005,9 +966,15 @@ bool Object::defineOwnProperty2(ExecutionContext *ctx, uint index, const Propert
if (!extensible)
goto reject;
// clause 4
- Property *pd = arrayInsert(index, attrs);
- *pd = p;
- pd->fullyPopulated(&attrs);
+ Property pp(p);
+ pp.fullyPopulated(&attrs);
+ if (attrs == Attr_Data) {
+ Scope scope(ctx);
+ ScopedValue v(scope, pp.value);
+ arraySet(index, v);
+ } else {
+ arraySet(index, pp, attrs);
+ }
return true;
}
@@ -1024,11 +991,11 @@ bool Object::__defineOwnProperty__(ExecutionContext *ctx, Property *current, con
if (attrs.isEmpty())
return true;
- PropertyAttributes cattrs = Attr_Data;
+ PropertyAttributes cattrs;
if (!member.isNull())
cattrs = internalClass->propertyData[current - memberData];
- else if (arrayData.attributes)
- cattrs = arrayData.attributes[current - arrayData.data];
+ else
+ cattrs = arrayData->attrs ? arrayData->attrs[current - arrayData->data] : Attr_Data;
// clause 6
if (p.isSubset(attrs, *current, cattrs))
@@ -1084,10 +1051,7 @@ bool Object::__defineOwnProperty__(ExecutionContext *ctx, Property *current, con
if (!member.isNull()) {
internalClass = internalClass->changeMember(member.getPointer(), cattrs);
} else {
- if (cattrs != Attr_Data)
- ensureArrayAttributes();
- if (arrayData.attributes)
- arrayData.attributes[current - arrayData.data] = cattrs;
+ arrayData->setAttributes(current - arrayData->data, cattrs);
}
if (attrs.isAccessor())
hasAccessorProperty = 1;
@@ -1113,7 +1077,7 @@ void Object::copyArrayData(Object *other)
Scope scope(engine());
if (other->protoHasArray() || other->hasAccessorProperty) {
- uint len = other->arrayLength();
+ uint len = other->getLength();
Q_ASSERT(len);
ScopedValue v(scope);
@@ -1121,313 +1085,97 @@ void Object::copyArrayData(Object *other)
arraySet(i, (v = other->getIndexed(i)));
}
} else {
- arrayReserve(other->arrayData.length);
- arrayData.length = other->arrayData.length;
- memcpy(arrayData.data, other->arrayData.data, arrayData.length*sizeof(Property));
- }
-
- arrayData.offset = 0;
+ Q_ASSERT(!arrayData && other->arrayData);
+ if (other->arrayType() == ArrayData::Sparse) {
+ SparseArrayData *od = static_cast<SparseArrayData *>(other->arrayData);
+ SparseArrayData *dd = new SparseArrayData;
+ dd->type = ArrayData::Sparse;
+ dd->sparse = new SparseArray(*od->sparse);
+ dd->freeList = od->freeList;
+ arrayData = dd;
+ }
+ arrayReserve(other->arrayData->len);
+ arrayData->len = other->arrayData->len;
+ // ### correctly deal with accessor properties
+ memcpy(arrayData->data, other->arrayData->data, arrayData->len*sizeof(Property));
- if (other->arrayData.sparse) {
- flags &= ~SimpleArray;
- arrayData.sparse = new SparseArray(*other->arrayData.sparse);
- arrayData.freeList = other->arrayData.freeList;
+ arrayData->offset = 0;
}
-
- setArrayLengthUnchecked(other->arrayLength());
+ setArrayLengthUnchecked(other->getLength());
}
-
-ReturnedValue Object::arrayIndexOf(const ValueRef v, uint fromIndex, uint endIndex, ExecutionContext *ctx, Object *o)
+uint Object::getLength(const Managed *m)
{
- Q_UNUSED(ctx);
-
- Scope scope(engine());
- ScopedValue value(scope);
-
- if (!(o->flags & SimpleArray) || o->protoHasArray()) {
- // lets be safe and slow
- for (uint i = fromIndex; i < endIndex; ++i) {
- bool exists;
- value = o->getIndexed(i, &exists);
- if (scope.hasException())
- return Encode::undefined();
- if (exists && __qmljs_strict_equal(value, v))
- return Encode(i);
- }
- } else if (arrayData.sparse) {
- for (SparseArrayNode *n = arrayData.sparse->lowerBound(fromIndex); n != arrayData.sparse->end() && n->key() < endIndex; n = n->nextNode()) {
- value = o->getValue(arrayData.data + n->value, arrayData.attributes ? arrayData.attributes[n->value] : Attr_Data);
- if (scope.hasException())
- return Encode::undefined();
- if (__qmljs_strict_equal(value, v))
- return Encode(n->key());
- }
- } else {
- if (endIndex > arrayData.length)
- endIndex = arrayData.length;
- Property *pd = arrayData.data;
- Property *end = pd + endIndex;
- pd += fromIndex;
- while (pd < end) {
- if (!pd->value.isEmpty()) {
- value = o->getValue(pd, arrayData.attributes ? arrayData.attributes[pd - arrayData.data] : Attr_Data);
- if (scope.hasException())
- return Encode::undefined();
- if (__qmljs_strict_equal(value, v))
- return Encode((uint)(pd - arrayData.data));
- }
- ++pd;
- }
- }
- return Encode(-1);
+ Scope scope(m->engine());
+ ScopedValue v(scope, const_cast<Managed *>(m)->get(scope.engine->id_length));
+ return v->toUInt32();
}
-void Object::arrayConcat(const ArrayObject *other)
+bool Object::setArrayLength(uint newLen)
{
- int newLen = arrayData.length + other->arrayLength();
- if (other->arrayData.sparse)
- initSparse();
- // ### copy attributes as well!
- if (arrayData.sparse) {
- if (other->arrayData.sparse) {
- for (const SparseArrayNode *it = other->arrayData.sparse->begin(); it != other->arrayData.sparse->end(); it = it->nextNode())
- arraySet(arrayData.length + it->key(), other->arrayData.data + it->value);
- } else {
- int oldSize = arrayData.length;
- arrayReserve(oldSize + other->arrayLength());
- memcpy(arrayData.data + oldSize, other->arrayData.data, other->arrayLength()*sizeof(Property));
- if (arrayData.attributes)
- std::fill(arrayData.attributes + oldSize, arrayData.attributes + oldSize + other->arrayLength(), PropertyAttributes(Attr_Data));
- for (uint i = 0; i < other->arrayLength(); ++i) {
- SparseArrayNode *n = arrayData.sparse->insert(arrayData.length + i);
- n->value = oldSize + i;
- }
- }
+ Q_ASSERT(isArrayObject());
+ const Property *lengthProperty = memberData + ArrayObject::LengthPropertyIndex;
+ if (lengthProperty && !internalClass->propertyData[ArrayObject::LengthPropertyIndex].isWritable())
+ return false;
+ uint oldLen = getLength();
+ bool ok = true;
+ if (newLen < oldLen) {
+ uint l = arrayData->truncate(newLen);
+ if (l != newLen)
+ ok = false;
+ newLen = l;
} else {
- uint oldSize = arrayLength();
- arrayReserve(oldSize + other->arrayData.length);
- if (oldSize > arrayData.length) {
- for (uint i = arrayData.length; i < oldSize; ++i)
- arrayData.data[i].value = Primitive::emptyValue();
- }
- if (other->arrayData.attributes) {
- for (uint i = 0; i < other->arrayData.length; ++i) {
- bool exists;
- arrayData.data[oldSize + i].value = const_cast<ArrayObject *>(other)->getIndexed(i, &exists);
- arrayData.length = oldSize + i + 1;
- if (arrayData.attributes)
- arrayData.attributes[oldSize + i] = Attr_Data;
- if (!exists)
- arrayData.data[oldSize + i].value = Primitive::emptyValue();
- }
- } else {
- arrayData.length = oldSize + other->arrayData.length;
- memcpy(arrayData.data + oldSize, other->arrayData.data, other->arrayData.length*sizeof(Property));
- if (arrayData.attributes)
- std::fill(arrayData.attributes + oldSize, arrayData.attributes + oldSize + other->arrayData.length, PropertyAttributes(Attr_Data));
- }
+ if (newLen >= 0x100000)
+ initSparseArray();
}
setArrayLengthUnchecked(newLen);
+ return ok;
}
-void Object::arraySort(ExecutionContext *context, ObjectRef thisObject, const ValueRef comparefn, uint len)
+void Object::initSparseArray()
{
- if (!arrayData.length)
+ if (arrayType() == ArrayData::Sparse)
return;
- if (arrayData.sparse) {
- context->throwUnimplemented(QStringLiteral("Object::sort unimplemented for sparse arrays"));
+ SparseArrayData *data = new SparseArrayData;
+ data->type = ArrayData::Sparse;
+ data->sparse = new SparseArray;
+ if (!arrayData) {
+ arrayData = data;
return;
}
- if (len > arrayData.length)
- len = arrayData.length;
-
- // The spec says the sorting goes through a series of get,put and delete operations.
- // this implies that the attributes don't get sorted around.
- // behavior of accessor properties is implementation defined. We simply turn them all
- // into data properties and then sort. This is in line with the sentence above.
- if (arrayData.attributes) {
- for (uint i = 0; i < len; i++) {
- if ((arrayData.attributes && arrayData.attributes[i].isGeneric()) || arrayData.data[i].value.isEmpty()) {
- while (--len > i)
- if (!((arrayData.attributes && arrayData.attributes[len].isGeneric())|| arrayData.data[len].value.isEmpty()))
- break;
- arrayData.data[i].value = getValue(arrayData.data + len, arrayData.attributes[len]);
- arrayData.data[len].value = Primitive::emptyValue();
- if (arrayData.attributes) {
- arrayData.attributes[i] = Attr_Data;
- arrayData.attributes[len].clear();
- }
- } else if (arrayData.attributes[i].isAccessor()) {
- arrayData.data[i].value = getValue(arrayData.data + i, arrayData.attributes[i]);
- arrayData.attributes[i] = Attr_Data;
- }
- }
- }
-
- if (!(comparefn->isUndefined() || comparefn->asObject())) {
- context->throwTypeError();
- return;
+ uint oldOffset = arrayData->offset;
+ data->data = arrayData->data - arrayData->offset;
+ data->attrs = arrayData->attrs;
+ data->len = arrayData->len;
+ data->alloc = arrayData->alloc;
+ data->offset = 0;
+ arrayData->data = 0;
+ arrayData->attrs = 0;
+ delete arrayData;
+
+ uint *lastFree = &data->freeList;
+ for (uint i = 0; i < oldOffset; ++i) {
+ *lastFree = i;
+ lastFree = &data->data[i].value.uint_32;
}
-
- ArrayElementLessThan lessThan(context, thisObject, comparefn);
-
- if (!len)
- return;
- Property *begin = arrayData.data;
- std::sort(begin, begin + len, lessThan);
-}
-
-
-void Object::initSparse()
-{
- if (!arrayData.sparse) {
- flags &= ~SimpleArray;
- arrayData.sparse = new SparseArray;
- for (uint i = 0; i < arrayData.length; ++i) {
- if (!((arrayData.attributes && arrayData.attributes[i].isGeneric()) || arrayData.data[i].value.isEmpty())) {
- SparseArrayNode *n = arrayData.sparse->insert(i);
- n->value = i + arrayData.offset;
- }
- }
-
- uint off = arrayData.offset;
- if (!arrayData.offset) {
- arrayData.freeList = arrayData.length;
+ for (uint i = 0; i < data->len; ++i) {
+ if (!data->data[i + oldOffset].value.isEmpty()) {
+ SparseArrayNode *n = data->sparse->insert(i);
+ n->value = i + oldOffset;
} else {
- arrayData.freeList = 0;
- arrayData.data -= off;
- arrayData.alloc += off;
- int o = off;
- for (int i = 0; i < o - 1; ++i) {
- arrayData.data[i].value = Primitive::fromInt32(i + 1);
- }
- arrayData.data[o - 1].value = Primitive::fromInt32(arrayData.length + off);
- }
- for (uint i = arrayData.length + off; i < arrayData.alloc; ++i) {
- arrayData.data[i].value = Primitive::fromInt32(i + 1);
+ *lastFree = i + oldOffset;
+ lastFree = &data->data[i + oldOffset].value.uint_32;
}
}
-}
-
-void Object::arrayReserve(uint n)
-{
- if (n < 8)
- n = 8;
- if (n >= arrayData.alloc) {
- uint off;
- if (arrayData.sparse) {
- assert(arrayData.freeList == arrayData.alloc);
- // ### FIXME
- arrayData.length = arrayData.alloc;
- off = 0;
- } else {
- off = arrayData.offset;
- }
- arrayData.alloc = qMax(n, 2*arrayData.alloc);
- Property *newArrayData = new Property[arrayData.alloc + off];
- if (arrayData.data) {
- memcpy(newArrayData + off, arrayData.data, sizeof(Property)*arrayData.length);
- delete [] (arrayData.data - off);
- }
- arrayData.data = newArrayData + off;
- if (arrayData.sparse) {
- for (uint i = arrayData.freeList; i < arrayData.alloc; ++i) {
- arrayData.data[i].value = Primitive::emptyValue();
- arrayData.data[i].value = Primitive::fromInt32(i + 1);
- }
- }
-
- if (arrayData.attributes) {
- PropertyAttributes *newAttrs = new PropertyAttributes[arrayData.alloc];
- memcpy(newAttrs, arrayData.attributes, sizeof(PropertyAttributes)*arrayData.length);
- delete [] (arrayData.attributes - off);
-
- arrayData.attributes = newAttrs;
- if (arrayData.sparse) {
- for (uint i = arrayData.freeList; i < arrayData.alloc; ++i)
- arrayData.attributes[i] = Attr_Invalid;
- }
- }
+ for (uint i = data->len + oldOffset; i < data->alloc; ++i) {
+ *lastFree = i;
+ lastFree = &data->data[i].value.uint_32;
}
+ arrayData = data;
}
-void Object::ensureArrayAttributes()
-{
- if (arrayData.attributes)
- return;
-
- flags &= ~SimpleArray;
- uint off = arrayData.sparse ? 0 : arrayData.offset;
- arrayData.attributes = new PropertyAttributes[arrayData.alloc + off];
- arrayData.attributes += off;
- for (uint i = 0; i < arrayData.length; ++i)
- arrayData.attributes[i] = Attr_Data;
- for (uint i = arrayData.length; i < arrayData.alloc; ++i)
- arrayData.attributes[i] = Attr_Invalid;
-}
-
-
-bool Object::setArrayLength(uint newLen) {
- assert(isArrayObject());
- const Property *lengthProperty = memberData + ArrayObject::LengthPropertyIndex;
- if (lengthProperty && !internalClass->propertyData[ArrayObject::LengthPropertyIndex].isWritable())
- return false;
- uint oldLen = arrayLength();
- bool ok = true;
- if (newLen < oldLen) {
- if (arrayData.sparse) {
- SparseArrayNode *begin = arrayData.sparse->lowerBound(newLen);
- if (begin != arrayData.sparse->end()) {
- SparseArrayNode *it = arrayData.sparse->end()->previousNode();
- while (1) {
- Property &pd = arrayData.data[it->value];
- if (arrayData.attributes) {
- if (!arrayData.attributes[it->value].isConfigurable()) {
- ok = false;
- newLen = it->key() + 1;
- break;
- } else {
- arrayData.attributes[it->value].clear();
- }
- }
- pd.value.tag = Value::Empty_Type;
- pd.value.int_32 = arrayData.freeList;
- arrayData.freeList = it->value;
- bool brk = (it == begin);
- SparseArrayNode *prev = it->previousNode();
- arrayData.sparse->erase(it);
- if (brk)
- break;
- it = prev;
- }
- }
- } else {
- Property *it = arrayData.data + arrayData.length;
- const Property *begin = arrayData.data + newLen;
- while (--it >= begin) {
- if (arrayData.attributes) {
- if (!arrayData.attributes[it - arrayData.data].isEmpty() && !arrayData.attributes[it - arrayData.data].isConfigurable()) {
- ok = false;
- newLen = it - arrayData.data + 1;
- break;
- } else {
- arrayData.attributes[it - arrayData.data].clear();
- }
- it->value = Primitive::emptyValue();
- }
- }
- arrayData.length = newLen;
- }
- } else {
- if (newLen >= 0x100000)
- initSparse();
- }
- setArrayLengthUnchecked(newLen);
- return ok;
-}
DEFINE_MANAGED_VTABLE(ArrayObject);
@@ -1444,9 +1192,10 @@ ArrayObject::ArrayObject(ExecutionEngine *engine, const QStringList &list)
// elements converted to JS Strings.
int len = list.count();
arrayReserve(len);
+ ScopedValue v(scope);
for (int ii = 0; ii < len; ++ii) {
- arrayData.data[ii].value = Encode(engine->newString(list.at(ii)));
- arrayData.length = ii + 1;
+ arrayData->put(ii, (v = engine->newString(list.at(ii))));
+ arrayData->setLength(ii + 1);
}
setArrayLengthUnchecked(len);
}
@@ -1458,6 +1207,25 @@ void ArrayObject::init(ExecutionEngine *engine)
memberData[LengthPropertyIndex].value = Primitive::fromInt32(0);
}
+ReturnedValue ArrayObject::getLookup(Managed *m, Lookup *l)
+{
+ if (l->name->equals(m->engine()->id_length)) {
+ // special case, as the property is on the object itself
+ l->getter = Lookup::arrayLengthGetter;
+ ArrayObject *a = static_cast<ArrayObject *>(m);
+ return a->memberData[ArrayObject::LengthPropertyIndex].value.asReturnedValue();
+ }
+ return Object::getLookup(m, l);
+}
+
+uint ArrayObject::getLength(const Managed *m)
+{
+ const ArrayObject *a = static_cast<const ArrayObject *>(m);
+ if (a->memberData[ArrayObject::LengthPropertyIndex].value.isInteger())
+ return a->memberData[ArrayObject::LengthPropertyIndex].value.integerValue();
+ return Primitive::toUInt32(a->memberData[ArrayObject::LengthPropertyIndex].value.doubleValue());
+}
+
QStringList ArrayObject::toQStringList() const
{
QStringList result;
@@ -1466,7 +1234,7 @@ QStringList ArrayObject::toQStringList() const
Scope scope(engine);
ScopedValue v(scope);
- uint32_t length = arrayLength();
+ uint32_t length = getLength();
for (uint32_t i = 0; i < length; ++i) {
v = const_cast<ArrayObject *>(this)->getIndexed(i);
result.append(v->toQStringNoThrow());