1 /****************************************************************************
3 ** Copyright (C) 2015 The Qt Company Ltd.
4 ** Contact: http://www.qt.io/licensing/
6 ** This file is part of the QtQml module of the Qt Toolkit.
8 ** $QT_BEGIN_LICENSE:LGPL21$
9 ** Commercial License Usage
10 ** Licensees holding valid commercial Qt licenses may use this file in
11 ** accordance with the commercial license agreement provided with the
12 ** Software or, alternatively, in accordance with the terms contained in
13 ** a written agreement between you and The Qt Company. For licensing terms
14 ** and conditions see http://www.qt.io/terms-conditions. For further
15 ** information use the contact form at http://www.qt.io/contact-us.
17 ** GNU Lesser General Public License Usage
18 ** Alternatively, this file may be used under the terms of the GNU Lesser
19 ** General Public License version 2.1 or version 3 as published by the Free
20 ** Software Foundation and appearing in the file LICENSE.LGPLv21 and
21 ** LICENSE.LGPLv3 included in the packaging of this file. Please review the
22 ** following information to ensure the GNU Lesser General Public License
23 ** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
24 ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
26 ** As a special exception, The Qt Company gives you certain additional
27 ** rights. These rights are described in The Qt Company LGPL Exception
28 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
32 ****************************************************************************/
34 #include "qv4object_p.h"
35 #include "qv4jsir_p.h"
36 #include "qv4isel_p.h"
37 #include "qv4objectproto_p.h"
38 #include "qv4stringobject_p.h"
39 #include "qv4argumentsobject_p.h"
40 #include <private/qv4mm_p.h>
41 #include "qv4lookup_p.h"
42 #include "qv4scopedvalue_p.h"
43 #include "qv4memberdata_p.h"
44 #include "qv4objectiterator_p.h"
45 #include "qv4identifier_p.h"
46 #include "qv4string_p.h"
52 DEFINE_OBJECT_VTABLE(Object);
54 Heap::Object::Object(InternalClass *internalClass, QV4::Object *prototype)
55 : internalClass(internalClass),
56 prototype(prototype ? prototype->d() : 0)
58 if (internalClass->size) {
59 Scope scope(internalClass->engine);
60 ScopedObject o(scope, this);
61 o->ensureMemberIndex(internalClass->engine, internalClass->size);
65 bool Object::setPrototype(Object *proto)
67 Heap::Object *pp = proto ? proto->d() : 0;
73 d()->prototype = proto ? proto->d() : 0;
77 void Object::put(ExecutionEngine *engine, const QString &name, const Value &value)
80 ScopedString n(scope, engine->newString(name));
84 ReturnedValue Object::getValue(const Value &thisObject, const Property *p, PropertyAttributes attrs)
86 if (!attrs.isAccessor())
87 return p->value.asReturnedValue();
89 return Encode::undefined();
91 Scope scope(p->getter()->internalClass->engine);
92 ScopedFunctionObject getter(scope, p->getter());
93 ScopedCallData callData(scope);
94 callData->thisObject = thisObject;
95 return getter->call(callData);
98 void Object::putValue(Property *pd, PropertyAttributes attrs, const Value &value)
100 if (internalClass()->engine->hasException)
103 if (attrs.isAccessor()) {
104 if (Heap::FunctionObject *set = pd->setter()) {
105 Scope scope(set->internalClass->engine);
106 ScopedFunctionObject setter(scope, set);
107 ScopedCallData callData(scope, 1);
108 callData->args[0] = value;
109 callData->thisObject = this;
110 setter->call(callData);
116 if (!attrs.isWritable())
123 if (engine()->currentContext()->strictMode)
124 engine()->throwTypeError();
127 void Object::defineDefaultProperty(const QString &name, const Value &value)
129 ExecutionEngine *e = engine();
131 ScopedString s(scope, e->newIdentifier(name));
132 defineDefaultProperty(s, value);
135 void Object::defineDefaultProperty(const QString &name, ReturnedValue (*code)(CallContext *), int argumentCount)
137 ExecutionEngine *e = engine();
139 ScopedString s(scope, e->newIdentifier(name));
140 ScopedContext global(scope, e->rootContext());
141 ScopedFunctionObject function(scope, BuiltinFunction::create(global, s, code));
142 function->defineReadonlyProperty(e->id_length(), Primitive::fromInt32(argumentCount));
143 defineDefaultProperty(s, function);
146 void Object::defineDefaultProperty(String *name, ReturnedValue (*code)(CallContext *), int argumentCount)
148 ExecutionEngine *e = engine();
150 ScopedContext global(scope, e->rootContext());
151 ScopedFunctionObject function(scope, BuiltinFunction::create(global, name, code));
152 function->defineReadonlyProperty(e->id_length(), Primitive::fromInt32(argumentCount));
153 defineDefaultProperty(name, function);
156 void Object::defineAccessorProperty(const QString &name, ReturnedValue (*getter)(CallContext *), ReturnedValue (*setter)(CallContext *))
158 ExecutionEngine *e = engine();
160 ScopedString s(scope, e->newIdentifier(name));
161 defineAccessorProperty(s, getter, setter);
164 void Object::defineAccessorProperty(String *name, ReturnedValue (*getter)(CallContext *), ReturnedValue (*setter)(CallContext *))
166 ExecutionEngine *v4 = engine();
167 QV4::Scope scope(v4);
168 ScopedProperty p(scope);
169 ScopedContext global(scope, scope.engine->rootContext());
170 p->setGetter(ScopedFunctionObject(scope, (getter ? BuiltinFunction::create(global, name, getter) : 0)));
171 p->setSetter(ScopedFunctionObject(scope, (setter ? BuiltinFunction::create(global, name, setter) : 0)));
172 insertMember(name, p, QV4::Attr_Accessor|QV4::Attr_NotConfigurable|QV4::Attr_NotEnumerable);
175 void Object::defineReadonlyProperty(const QString &name, const Value &value)
177 QV4::ExecutionEngine *e = engine();
179 ScopedString s(scope, e->newIdentifier(name));
180 defineReadonlyProperty(s, value);
183 void Object::defineReadonlyProperty(String *name, const Value &value)
185 insertMember(name, value, Attr_ReadOnly);
188 void Object::markObjects(Heap::Base *that, ExecutionEngine *e)
190 Heap::Object *o = static_cast<Heap::Object *>(that);
193 o->memberData->mark(e);
195 o->arrayData->mark(e);
197 o->prototype->mark(e);
200 void Object::ensureMemberIndex(uint idx)
202 d()->memberData = MemberData::reallocate(engine(), d()->memberData, idx);
205 void Object::insertMember(String *s, const Property *p, PropertyAttributes attributes)
208 InternalClass::addMember(this, s, attributes, &idx);
211 ensureMemberIndex(internalClass()->size);
213 if (attributes.isAccessor()) {
214 Property *pp = propertyAt(idx);
215 pp->value = p->value;
218 d()->memberData->data[idx] = p->value;
223 void Object::getOwnProperty(String *name, PropertyAttributes *attrs, Property *p)
225 uint idx = name->asArrayIndex();
227 return getOwnProperty(idx, attrs, p);
229 uint member = internalClass()->find(name);
230 if (member < UINT_MAX) {
231 *attrs = internalClass()->propertyData[member];
233 p->copy(propertyAt(member), *attrs);
238 *attrs = Attr_Invalid;
242 void Object::getOwnProperty(uint index, PropertyAttributes *attrs, Property *p)
244 Property *pd = arrayData() ? arrayData()->getProperty(index) : 0;
246 *attrs = arrayData()->attributes(index);
251 if (isStringObject()) {
252 *attrs = Attr_NotConfigurable|Attr_NotWritable;
254 p->value = static_cast<StringObject *>(this)->getIndex(index);
259 *attrs = Attr_Invalid;
264 Property *Object::__getPropertyDescriptor__(String *name, PropertyAttributes *attrs) const
266 Q_ASSERT(name->asArrayIndex() == UINT_MAX);
268 const Heap::Object *o = d();
270 uint idx = o->internalClass->find(name);
271 if (idx < UINT_MAX) {
273 *attrs = o->internalClass->propertyData[idx];
274 return const_cast<Property *>(o->propertyAt(idx));
280 *attrs = Attr_Invalid;
284 Property *Object::__getPropertyDescriptor__(uint index, PropertyAttributes *attrs) const
286 const Heap::Object *o = d();
288 Property *p = o->arrayData ? o->arrayData->getProperty(index) : 0;
290 *attrs = o->arrayData->attributes(index);
293 if (o->vtable()->type == Type_StringObject) {
294 if (index < static_cast<const Heap::StringObject *>(o)->length()) {
295 // this is an evil hack, but it works, as the method is only ever called from putIndexed,
296 // where we don't use the returned pointer there for non writable attributes
297 *attrs = (Attr_NotWritable|Attr_NotConfigurable);
298 return reinterpret_cast<Property *>(0x1);
304 *attrs = Attr_Invalid;
308 bool Object::hasProperty(String *name) const
310 uint idx = name->asArrayIndex();
312 return hasProperty(idx);
314 Scope scope(engine());
315 ScopedObject o(scope, d());
317 if (o->hasOwnProperty(name))
326 bool Object::hasProperty(uint index) const
328 Scope scope(engine());
329 ScopedObject o(scope, d());
331 if (o->hasOwnProperty(index))
340 bool Object::hasOwnProperty(String *name) const
342 uint idx = name->asArrayIndex();
344 return hasOwnProperty(idx);
346 if (internalClass()->find(name) < UINT_MAX)
348 if (!query(name).isEmpty())
353 bool Object::hasOwnProperty(uint index) const
355 if (arrayData() && !arrayData()->isEmpty(index))
358 if (isStringObject()) {
359 if (index < static_cast<const StringObject *>(this)->length())
362 if (!queryIndexed(index).isEmpty())
367 ReturnedValue Object::construct(const Managed *m, CallData *)
369 return static_cast<const Object *>(m)->engine()->throwTypeError();
372 ReturnedValue Object::call(const Managed *m, CallData *)
374 return static_cast<const Object *>(m)->engine()->throwTypeError();
377 ReturnedValue Object::get(const Managed *m, String *name, bool *hasProperty)
379 return static_cast<const Object *>(m)->internalGet(name, hasProperty);
382 ReturnedValue Object::getIndexed(const Managed *m, uint index, bool *hasProperty)
384 return static_cast<const Object *>(m)->internalGetIndexed(index, hasProperty);
387 void Object::put(Managed *m, String *name, const Value &value)
389 static_cast<Object *>(m)->internalPut(name, value);
392 void Object::putIndexed(Managed *m, uint index, const Value &value)
394 static_cast<Object *>(m)->internalPutIndexed(index, value);
397 PropertyAttributes Object::query(const Managed *m, String *name)
399 uint idx = name->asArrayIndex();
401 return queryIndexed(m, idx);
403 const Object *o = static_cast<const Object *>(m);
404 idx = o->internalClass()->find(name);
406 return o->internalClass()->propertyData[idx];
411 PropertyAttributes Object::queryIndexed(const Managed *m, uint index)
413 const Object *o = static_cast<const Object *>(m);
414 if (o->arrayData() && !o->arrayData()->isEmpty(index))
415 return o->arrayData()->attributes(index);
417 if (o->isStringObject()) {
418 if (index < static_cast<const StringObject *>(o)->length())
419 return (Attr_NotWritable|Attr_NotConfigurable);
424 bool Object::deleteProperty(Managed *m, String *name)
426 return static_cast<Object *>(m)->internalDeleteProperty(name);
429 bool Object::deleteIndexedProperty(Managed *m, uint index)
431 return static_cast<Object *>(m)->internalDeleteIndexedProperty(index);
434 ReturnedValue Object::getLookup(const Managed *m, Lookup *l)
436 const Object *o = static_cast<const Object *>(m);
437 PropertyAttributes attrs;
438 ReturnedValue v = l->lookup(o, &attrs);
439 if (v != Primitive::emptyValue().asReturnedValue()) {
440 if (attrs.isData()) {
442 l->getter = Lookup::getter0;
443 else if (l->level == 1)
444 l->getter = Lookup::getter1;
445 else if (l->level == 2)
446 l->getter = Lookup::getter2;
448 l->getter = Lookup::getterFallback;
452 l->getter = Lookup::getterAccessor0;
453 else if (l->level == 1)
454 l->getter = Lookup::getterAccessor1;
455 else if (l->level == 2)
456 l->getter = Lookup::getterAccessor2;
458 l->getter = Lookup::getterFallback;
462 return Encode::undefined();
465 void Object::setLookup(Managed *m, Lookup *l, const Value &value)
467 Scope scope(static_cast<Object *>(m)->engine());
468 ScopedObject o(scope, static_cast<Object *>(m));
469 ScopedString name(scope, scope.engine->currentContext()->compilationUnit->runtimeStrings[l->nameIndex]);
471 InternalClass *c = o->internalClass();
472 uint idx = c->find(name);
473 if (!o->isArrayObject() || idx != Heap::ArrayObject::LengthPropertyIndex) {
474 if (idx != UINT_MAX && o->internalClass()->propertyData[idx].isData() && o->internalClass()->propertyData[idx].isWritable()) {
475 l->classList[0] = o->internalClass();
477 l->setter = Lookup::setter0;
478 o->memberData()->data[idx] = value;
482 if (idx != UINT_MAX) {
483 o->putValue(o->propertyAt(idx), o->internalClass()->propertyData[idx], value);
490 if (o->internalClass() == c)
492 idx = o->internalClass()->find(name);
496 l->classList[3] = o->internalClass();
498 if (!o->prototype()) {
499 l->setter = Lookup::setterInsert0;
503 l->classList[1] = o->internalClass();
504 if (!o->prototype()) {
505 l->setter = Lookup::setterInsert1;
509 l->classList[2] = o->internalClass();
510 if (!o->prototype()) {
511 l->setter = Lookup::setterInsert2;
514 l->setter = Lookup::setterGeneric;
517 void Object::advanceIterator(Managed *m, ObjectIterator *it, Value *name, uint *index, Property *pd, PropertyAttributes *attrs)
519 Object *o = static_cast<Object *>(m);
523 if (o->arrayData()) {
525 it->arrayNode = o->sparseBegin();
529 while (it->arrayNode != o->sparseEnd()) {
530 int k = it->arrayNode->key();
531 uint pidx = it->arrayNode->value;
532 Heap::SparseArrayData *sa = o->d()->arrayData.cast<Heap::SparseArrayData>();
533 Property *p = reinterpret_cast<Property *>(sa->arrayData + pidx);
534 it->arrayNode = it->arrayNode->nextNode();
535 PropertyAttributes a = sa->attrs ? sa->attrs[pidx] : Attr_Data;
536 if (!(it->flags & ObjectIterator::EnumerableOnly) || a.isEnumerable()) {
537 it->arrayIndex = k + 1;
545 it->arrayIndex = UINT_MAX;
548 while (it->arrayIndex < o->d()->arrayData->len) {
549 Heap::SimpleArrayData *sa = o->d()->arrayData.cast<Heap::SimpleArrayData>();
550 Value &val = sa->data(it->arrayIndex);
551 PropertyAttributes a = o->arrayData()->attributes(it->arrayIndex);
554 && (!(it->flags & ObjectIterator::EnumerableOnly) || a.isEnumerable())) {
555 *index = it->arrayIndex - 1;
563 while (it->memberIndex < o->internalClass()->size) {
564 Identifier *n = o->internalClass()->nameMap.at(it->memberIndex);
566 // accessor properties have a dummy entry with n == 0
571 Property *p = o->propertyAt(it->memberIndex);
572 PropertyAttributes a = o->internalClass()->propertyData[it->memberIndex];
574 if (!(it->flags & ObjectIterator::EnumerableOnly) || a.isEnumerable()) {
575 name->setM(o->engine()->newString(n->string));
582 *attrs = PropertyAttributes();
586 ReturnedValue Object::internalGet(String *name, bool *hasProperty) const
588 uint idx = name->asArrayIndex();
590 return getIndexed(idx, hasProperty);
592 Scope scope(engine());
593 name->makeIdentifier(scope.engine);
595 ScopedObject o(scope, this);
597 uint idx = o->internalClass()->find(name);
598 if (idx < UINT_MAX) {
601 return getValue(o->propertyAt(idx), o->internalClass()->propertyData.at(idx));
608 *hasProperty = false;
609 return Encode::undefined();
612 ReturnedValue Object::internalGetIndexed(uint index, bool *hasProperty) const
615 PropertyAttributes attrs;
616 Scope scope(engine());
617 ScopedObject o(scope, this);
619 Property *p = o->arrayData() ? o->arrayData()->getProperty(index) : 0;
622 attrs = o->arrayData()->attributes(index);
625 if (o->isStringObject()) {
626 ScopedString str(scope, static_cast<StringObject *>(o.getPointer())->getIndex(index));
628 attrs = (Attr_NotWritable|Attr_NotConfigurable);
631 return str.asReturnedValue();
640 return getValue(pd, attrs);
644 *hasProperty = false;
645 return Encode::undefined();
650 void Object::internalPut(String *name, const Value &value)
652 if (internalClass()->engine->hasException)
655 uint idx = name->asArrayIndex();
657 return putIndexed(idx, value);
659 name->makeIdentifier(engine());
661 uint member = internalClass()->find(name);
663 PropertyAttributes attrs;
664 if (member < UINT_MAX) {
665 pd = propertyAt(member);
666 attrs = internalClass()->propertyData[member];
671 if (attrs.isAccessor()) {
675 } else if (!attrs.isWritable())
677 else if (isArrayObject() && name->equals(engine()->id_length())) {
679 uint l = value.asArrayLength(&ok);
681 engine()->throwRangeError(value);
684 ok = setArrayLength(l);
691 } else if (!prototype()) {
696 Scope scope(engine());
697 if ((pd = ScopedObject(scope, prototype())->__getPropertyDescriptor__(name, &attrs))) {
698 if (attrs.isAccessor()) {
701 } else if (!isExtensible() || !attrs.isWritable()) {
704 } else if (!isExtensible()) {
712 if (pd && attrs.isAccessor()) {
713 Q_ASSERT(pd->setter() != 0);
715 Scope scope(engine());
716 ScopedFunctionObject setter(scope, pd->setter());
717 ScopedCallData callData(scope, 1);
718 callData->args[0] = value;
719 callData->thisObject = this;
720 setter->call(callData);
724 insertMember(name, value);
728 if (engine()->currentContext()->strictMode) {
729 QString message = QStringLiteral("Cannot assign to read-only property \"");
730 message += name->toQString();
731 message += QLatin1Char('\"');
732 engine()->throwTypeError(message);
736 void Object::internalPutIndexed(uint index, const Value &value)
738 if (internalClass()->engine->hasException)
741 PropertyAttributes attrs;
743 Property *pd = arrayData() ? arrayData()->getProperty(index) : 0;
745 attrs = arrayData()->attributes(index);
747 if (!pd && isStringObject()) {
748 if (index < static_cast<StringObject *>(this)->length())
755 if (attrs.isAccessor()) {
759 } else if (!attrs.isWritable())
764 } else if (!prototype()) {
769 Scope scope(engine());
770 if ((pd = ScopedObject(scope, prototype())->__getPropertyDescriptor__(index, &attrs))) {
771 if (attrs.isAccessor()) {
774 } else if (!isExtensible() || !attrs.isWritable()) {
777 } else if (!isExtensible()) {
785 if (pd && attrs.isAccessor()) {
786 Q_ASSERT(pd->setter() != 0);
788 Scope scope(engine());
789 ScopedFunctionObject setter(scope, pd->setter());
790 ScopedCallData callData(scope, 1);
791 callData->args[0] = value;
792 callData->thisObject = this;
793 setter->call(callData);
797 arraySet(index, value);
801 if (engine()->currentContext()->strictMode)
802 engine()->throwTypeError();
806 bool Object::internalDeleteProperty(String *name)
808 if (internalClass()->engine->hasException)
811 uint idx = name->asArrayIndex();
813 return deleteIndexedProperty(idx);
815 name->makeIdentifier(engine());
817 uint memberIdx = internalClass()->find(name);
818 if (memberIdx != UINT_MAX) {
819 if (internalClass()->propertyData[memberIdx].isConfigurable()) {
820 InternalClass::removeMember(this, name->identifier());
823 if (engine()->currentContext()->strictMode)
824 engine()->throwTypeError();
831 bool Object::internalDeleteIndexedProperty(uint index)
833 Scope scope(engine());
834 if (scope.engine->hasException)
837 Scoped<ArrayData> ad(scope, arrayData());
838 if (!ad || ad->vtable()->del(this, index))
841 if (engine()->currentContext()->strictMode)
842 engine()->throwTypeError();
847 bool Object::__defineOwnProperty__(ExecutionEngine *engine, String *name, const Property *p, PropertyAttributes attrs)
849 uint idx = name->asArrayIndex();
851 return __defineOwnProperty__(engine, idx, p, attrs);
854 name->makeIdentifier(scope.engine);
857 PropertyAttributes *cattrs;
860 if (isArrayObject() && name->equals(engine->id_length())) {
861 Q_ASSERT(Heap::ArrayObject::LengthPropertyIndex == internalClass()->find(engine->id_length()));
862 Property *lp = propertyAt(Heap::ArrayObject::LengthPropertyIndex);
863 cattrs = internalClass()->propertyData.constData() + Heap::ArrayObject::LengthPropertyIndex;
864 if (attrs.isEmpty() || p->isSubset(attrs, lp, *cattrs))
866 if (!cattrs->isWritable() || attrs.type() == PropertyAttributes::Accessor || attrs.isConfigurable() || attrs.isEnumerable())
868 bool succeeded = true;
869 if (attrs.type() == PropertyAttributes::Data) {
871 uint l = p->value.asArrayLength(&ok);
873 ScopedValue v(scope, p->value);
874 engine->throwRangeError(v);
877 succeeded = setArrayLength(l);
879 if (attrs.hasWritable() && !attrs.isWritable())
880 cattrs->setWritable(false);
887 memberIndex = internalClass()->find(name);
888 current = (memberIndex < UINT_MAX) ? propertyAt(memberIndex) : 0;
889 cattrs = internalClass()->propertyData.constData() + memberIndex;
896 ScopedProperty pd(scope);
898 pd->fullyPopulated(&attrs);
899 insertMember(name, pd, attrs);
903 return __defineOwnProperty__(engine, memberIndex, name, p, attrs);
905 if (engine->currentContext()->strictMode)
906 engine->throwTypeError();
910 bool Object::__defineOwnProperty__(ExecutionEngine *engine, uint index, const Property *p, PropertyAttributes attrs)
913 if (isArrayObject() && index >= getLength() && !internalClass()->propertyData[Heap::ArrayObject::LengthPropertyIndex].isWritable())
916 if (ArgumentsObject::isNonStrictArgumentsObject(this))
917 return static_cast<ArgumentsObject *>(this)->defineOwnProperty(engine, index, p, attrs);
919 return defineOwnProperty2(engine, index, p, attrs);
921 if (engine->currentContext()->strictMode)
922 engine->throwTypeError();
926 bool Object::defineOwnProperty2(ExecutionEngine *engine, uint index, const Property *p, PropertyAttributes attrs)
928 bool hasProperty = 0;
932 hasProperty = arrayData()->getProperty(index);
933 if (!hasProperty && isStringObject())
934 hasProperty = (index < static_cast<StringObject *>(this)->length());
943 ScopedProperty pp(scope);
945 pp->fullyPopulated(&attrs);
946 if (attrs == Attr_Data) {
947 ScopedValue v(scope, pp->value);
950 arraySet(index, pp, attrs);
955 return __defineOwnProperty__(engine, index, 0, p, attrs);
957 if (engine->currentContext()->strictMode)
958 engine->throwTypeError();
962 bool Object::__defineOwnProperty__(ExecutionEngine *engine, uint index, String *member, const Property *p, PropertyAttributes attrs)
968 Property *current = 0;
969 PropertyAttributes cattrs;
971 current = propertyAt(index);
972 cattrs = internalClass()->propertyData[index];
973 } else if (arrayData()) {
974 current = arrayData()->getProperty(index);
975 cattrs = arrayData()->attributes(index);
979 if (p->isSubset(attrs, current, cattrs))
983 if (!cattrs.isConfigurable()) {
984 if (attrs.isConfigurable())
986 if (attrs.hasEnumerable() && attrs.isEnumerable() != cattrs.isEnumerable())
991 if (attrs.isGeneric() || current->value.isEmpty())
995 if (cattrs.isData() != attrs.isData()) {
997 if (!cattrs.isConfigurable())
999 if (cattrs.isData()) {
1001 cattrs.setType(PropertyAttributes::Accessor);
1002 cattrs.clearWritable();
1004 // need to convert the array and the slot
1006 Q_ASSERT(arrayData());
1007 setArrayAttributes(index, cattrs);
1008 current = arrayData()->getProperty(index);
1010 current->setGetter(0);
1011 current->setSetter(0);
1014 cattrs.setType(PropertyAttributes::Data);
1015 cattrs.setWritable(false);
1017 // need to convert the array and the slot
1018 setArrayAttributes(index, cattrs);
1019 current = arrayData()->getProperty(index);
1021 current->value = Primitive::undefinedValue();
1023 } else if (cattrs.isData() && attrs.isData()) { // clause 10
1024 if (!cattrs.isConfigurable() && !cattrs.isWritable()) {
1025 if (attrs.isWritable() || !current->value.sameValue(p->value))
1028 } else { // clause 10
1029 Q_ASSERT(cattrs.isAccessor() && attrs.isAccessor());
1030 if (!cattrs.isConfigurable()) {
1031 if (!p->value.isEmpty() && current->value.rawValue() != p->value.rawValue())
1033 if (!p->set.isEmpty() && current->set.rawValue() != p->set.rawValue())
1040 current->merge(cattrs, p, attrs);
1042 InternalClass::changeMember(this, member, cattrs);
1044 setArrayAttributes(index, cattrs);
1048 if (engine->currentContext()->strictMode)
1049 engine->throwTypeError();
1054 bool Object::__defineOwnProperty__(ExecutionEngine *engine, const QString &name, const Property *p, PropertyAttributes attrs)
1056 Scope scope(engine);
1057 ScopedString s(scope, engine->newString(name));
1058 return __defineOwnProperty__(engine, s, p, attrs);
1062 void Object::copyArrayData(Object *other)
1064 Q_ASSERT(isArrayObject());
1065 Scope scope(engine());
1067 if (other->protoHasArray() || ArgumentsObject::isNonStrictArgumentsObject(other) ||
1068 (other->arrayType() == Heap::ArrayData::Sparse && other->arrayData()->attrs)) {
1069 uint len = other->getLength();
1072 ScopedValue v(scope);
1073 for (uint i = 0; i < len; ++i) {
1074 arraySet(i, (v = other->getIndexed(i)));
1076 } else if (!other->arrayData()) {
1079 Q_ASSERT(!arrayData() && other->arrayData());
1080 ArrayData::realloc(this, other->d()->arrayData->type, other->d()->arrayData->alloc, false);
1081 if (other->arrayType() == Heap::ArrayData::Sparse) {
1082 Heap::ArrayData *od = other->d()->arrayData;
1083 Heap::ArrayData *dd = d()->arrayData;
1084 dd->sparse = new SparseArray(*od->sparse);
1085 dd->freeList = od->freeList;
1087 Heap::ArrayData *dd = d()->arrayData;
1088 dd->len = other->d()->arrayData->len;
1089 dd->offset = other->d()->arrayData->offset;
1091 memcpy(d()->arrayData->arrayData, other->d()->arrayData->arrayData, d()->arrayData->alloc*sizeof(Value));
1093 setArrayLengthUnchecked(other->getLength());
1096 uint Object::getLength(const Managed *m)
1098 Scope scope(static_cast<const Object *>(m)->engine());
1099 ScopedValue v(scope, static_cast<Object *>(const_cast<Managed *>(m))->get(scope.engine->id_length()));
1100 return v->toUInt32();
1103 bool Object::setArrayLength(uint newLen)
1105 Q_ASSERT(isArrayObject());
1106 if (!internalClass()->propertyData[Heap::ArrayObject::LengthPropertyIndex].isWritable())
1108 uint oldLen = getLength();
1110 if (newLen < oldLen) {
1114 uint l = arrayData()->vtable()->truncate(this, newLen);
1120 if (newLen >= 0x100000)
1123 setArrayLengthUnchecked(newLen);
1127 void Object::initSparseArray()
1129 if (arrayType() == Heap::ArrayData::Sparse)
1132 ArrayData::realloc(this, Heap::ArrayData::Sparse, 0, false);
1136 DEFINE_OBJECT_VTABLE(ArrayObject);
1138 Heap::ArrayObject::ArrayObject(ExecutionEngine *engine, const QStringList &list)
1139 : Heap::Object(engine->arrayClass, engine->arrayPrototype())
1142 Scope scope(engine);
1143 ScopedObject a(scope, this);
1145 // Converts a QStringList to JS.
1146 // The result is a new Array object with length equal to the length
1147 // of the QStringList, and the elements being the QStringList's
1148 // elements converted to JS Strings.
1149 int len = list.count();
1150 a->arrayReserve(len);
1151 ScopedValue v(scope);
1152 for (int ii = 0; ii < len; ++ii)
1153 a->arrayPut(ii, (v = engine->newString(list.at(ii))));
1154 a->setArrayLengthUnchecked(len);
1157 ReturnedValue ArrayObject::getLookup(const Managed *m, Lookup *l)
1159 Scope scope(static_cast<const Object *>(m)->engine());
1160 ScopedString name(scope, scope.engine->currentContext()->compilationUnit->runtimeStrings[l->nameIndex]);
1161 if (name->equals(scope.engine->id_length())) {
1162 // special case, as the property is on the object itself
1163 l->getter = Lookup::arrayLengthGetter;
1164 const ArrayObject *a = static_cast<const ArrayObject *>(m);
1165 return a->memberData()->data[Heap::ArrayObject::LengthPropertyIndex].asReturnedValue();
1167 return Object::getLookup(m, l);
1170 uint ArrayObject::getLength(const Managed *m)
1172 const ArrayObject *a = static_cast<const ArrayObject *>(m);
1173 if (a->memberData()->data[Heap::ArrayObject::LengthPropertyIndex].isInteger())
1174 return a->memberData()->data[Heap::ArrayObject::LengthPropertyIndex].integerValue();
1175 return Primitive::toUInt32(a->memberData()->data[Heap::ArrayObject::LengthPropertyIndex].doubleValue());
1178 QStringList ArrayObject::toQStringList() const
1182 QV4::ExecutionEngine *engine = internalClass()->engine;
1183 Scope scope(engine);
1184 ScopedValue v(scope);
1186 uint length = getLength();
1187 for (uint i = 0; i < length; ++i) {
1188 v = const_cast<ArrayObject *>(this)->getIndexed(i);
1189 result.append(v->toQStringNoThrow());