aboutsummaryrefslogtreecommitdiffstats
path: root/src/qml/jsruntime/qv4object.cpp
diff options
context:
space:
mode:
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());