7#include <private/qv4argumentsobject_p.h>
8#include <private/qv4identifiertable_p.h>
9#include <private/qv4jscall_p.h>
10#include <private/qv4lookup_p.h>
11#include <private/qv4memberdata_p.h>
12#include <private/qv4mm_p.h>
13#include <private/qv4proxy_p.h>
14#include <private/qv4scopedvalue_p.h>
15#include <private/qv4stackframe_p.h>
16#include <private/qv4stringobject_p.h>
17#include <private/qv4symbol_p.h>
19#include <QtCore/qloggingcategory.h>
24using namespace Qt::Literals::StringLiterals;
28DEFINE_OBJECT_VTABLE(Object);
30void Object::setInternalClass(Heap::InternalClass *ic)
32 Q_ASSERT(ic && ic->vtable);
33 Heap::Object *p = d();
35 if (ic->numRedundantTransitions < p->internalClass.get()->numRedundantTransitions) {
38 Scope scope(engine());
41 Scoped<InternalClass> newIC(scope, ic);
45 Scoped<MemberData> newMembers(scope, MemberData::allocate(scope.engine, ic->size));
46 for (uint i = 0; i < ic->size; ++i) {
48 const PropertyKey key = ic->nameMap.at(i);
50 newMembers->set(scope.engine, i,
51 QV4::Value::fromReturnedValue(key.isValid() ? get(key) : Encode::undefined()));
54 p->internalClass.set(scope.engine, ic);
55 const uint nInline = p->vtable()->nInlineProperties;
57 if (ic->size > nInline)
58 p->memberData.set(scope.engine, MemberData::allocate(ic->engine, ic->size - nInline));
60 p->memberData.set(scope.engine,
nullptr);
62 const auto &memberValues = newMembers->d()->values;
63 for (uint i = 0; i < ic->size; ++i)
64 setProperty(i, memberValues[i]);
69 p->internalClass.set(ic->engine, ic);
70 const uint nInline = p->vtable()->nInlineProperties;
71 if (ic->size > nInline) {
72 const uint requiredSize = ic->size - nInline;
73 if ((p->memberData ? p->memberData->values.size : 0) < requiredSize) {
74 p->memberData.set(ic->engine, MemberData::allocate(
75 ic->engine, requiredSize, p->memberData));
82 if (ic->engine->isInitialized && ic->isUsedAsProto())
83 ic->updateProtoUsage(p);
87void Object::getProperty(
const InternalClassEntry &entry, Property *p)
const
89 p->value = *propertyData(entry.index);
90 if (entry.attributes.isAccessor())
91 p->set = *propertyData(entry.setterIndex);
94void Object::setProperty(
const InternalClassEntry &entry,
const Property *p)
96 setProperty(entry.index, p->value);
97 if (entry.attributes.isAccessor())
98 setProperty(entry.setterIndex, p->set);
101void Heap::Object::setUsedAsProto()
103 internalClass.set(internalClass->engine, internalClass->asProtoClass());
106ReturnedValue Object::getValueAccessor(
const Value *thisObject,
const Value &v, PropertyAttributes attrs)
108 if (!attrs.isAccessor())
109 return v.asReturnedValue();
110 const QV4::FunctionObject *f = v.as<FunctionObject>();
112 return Encode::undefined();
114 Scope scope(f->engine());
115 JSCallArguments jsCallData(scope);
117 *jsCallData.thisObject = *thisObject;
118 return checkedResult(scope.engine, f->call(jsCallData));
121bool Object::putValue(uint memberIndex, PropertyAttributes attrs,
const Value &value)
123 Heap::InternalClass *ic = internalClass();
124 if (ic->engine->hasException)
127 if (attrs.isAccessor()) {
128 const FunctionObject *set = propertyData(memberIndex)->as<FunctionObject>();
130 Scope scope(ic->engine);
131 ScopedFunctionObject setter(scope, set);
132 JSCallArguments jsCallData(scope, 1);
133 jsCallData.args[0] = value;
134 *jsCallData.thisObject =
this;
135 setter->call(jsCallData);
136 return !ic->engine->hasException;
141 if (!attrs.isWritable())
144 setProperty(memberIndex, value);
148void Object::defineDefaultProperty(
const QString &name,
const Value &value, PropertyAttributes attributes)
150 ExecutionEngine *e = engine();
152 ScopedString s(scope, e->newIdentifier(name));
153 defineDefaultProperty(s, value, attributes);
156void Object::defineDefaultProperty(
const QString &name, VTable::Call code,
157 int argumentCount, PropertyAttributes attributes)
159 ExecutionEngine *e = engine();
161 ScopedString s(scope, e->newIdentifier(name));
162 ScopedFunctionObject function(scope, FunctionObject::createBuiltinFunction(e, s, code, argumentCount));
163 defineDefaultProperty(s, function, attributes);
166void Object::defineDefaultProperty(StringOrSymbol *nameOrSymbol, VTable::Call code,
167 int argumentCount, PropertyAttributes attributes)
169 ExecutionEngine *e = engine();
171 ScopedFunctionObject function(scope, FunctionObject::createBuiltinFunction(e, nameOrSymbol, code, argumentCount));
172 defineDefaultProperty(nameOrSymbol, function, attributes);
175void Object::defineAccessorProperty(
const QString &name, VTable::Call getter, VTable::Call setter)
177 ExecutionEngine *e = engine();
179 ScopedString s(scope, e->newIdentifier(name));
180 defineAccessorProperty(s, getter, setter);
183void Object::defineAccessorProperty(StringOrSymbol *name, VTable::Call getter, VTable::Call setter)
185 ExecutionEngine *v4 = engine();
186 QV4::Scope scope(v4);
187 ScopedProperty p(scope);
188 QString n = name->toQString();
189 if (!n.isEmpty() && n.at(0) ==
'@'_L1)
190 n =
'['_L1 + QStringView{n}.mid(1) +
']'_L1;
192 ScopedString getName(scope, v4->newString(
"get "_L1 + n));
193 p->setGetter(ScopedFunctionObject(scope, FunctionObject::createBuiltinFunction(v4, getName, getter, 0)));
195 p->setGetter(
nullptr);
198 ScopedString setName(scope, v4->newString(
"set "_L1 + n));
199 p->setSetter(ScopedFunctionObject(scope, FunctionObject::createBuiltinFunction(v4, setName, setter, 0)));
201 p->setSetter(
nullptr);
203 insertMember(name, p, QV4::Attr_Accessor|QV4::Attr_NotEnumerable);
208void Object::defineReadonlyProperty(
const QString &name,
const Value &value)
210 QV4::ExecutionEngine *e = engine();
212 ScopedString s(scope, e->newIdentifier(name));
213 defineReadonlyProperty(s, value);
216void Object::defineReadonlyProperty(String *name,
const Value &value)
218 insertMember(name, value, Attr_ReadOnly);
221void Object::defineReadonlyConfigurableProperty(
const QString &name,
const Value &value)
223 QV4::ExecutionEngine *e = engine();
225 ScopedString s(scope, e->newIdentifier(name));
226 defineReadonlyConfigurableProperty(s, value);
229void Object::defineReadonlyConfigurableProperty(StringOrSymbol *name,
const Value &value)
231 insertMember(name, value, Attr_ReadOnly_ButConfigurable);
234void Object::addSymbolSpecies()
236 Scope scope(engine());
237 ScopedProperty p(scope);
238 p->setGetter(scope.engine->getSymbolSpecies());
239 p->setSetter(
nullptr);
240 insertMember(scope.engine->symbol_species(), p, QV4::Attr_Accessor|QV4::Attr_NotWritable|QV4::Attr_NotEnumerable);
243void Heap::Object::markObjects(Heap::Base *b, MarkStack *stack)
245 Base::markObjects(b, stack);
246 Object *o =
static_cast<Object *>(b);
248 o->memberData->mark(stack);
250 o->arrayData->mark(stack);
251 uint nInline = o->vtable()->nInlineProperties;
252 Value *v =
reinterpret_cast<Value *>(o) + o->vtable()->inlinePropertyOffset;
253 const Value *end = v + nInline;
260void Object::insertMember(StringOrSymbol *s,
const Property *p, PropertyAttributes attributes)
262 InternalClassEntry idx;
263 PropertyKey key = s->toPropertyKey();
264 Heap::InternalClass::addMember(
this, key, attributes, &idx);
266 setProperty(idx.index, p->value);
267 if (attributes.isAccessor())
268 setProperty(idx.setterIndex, p->set);
271void Object::setPrototypeUnchecked(
const Object *p)
273 setInternalClass(internalClass()->changePrototype(p ? p->d() :
nullptr));
277PropertyIndex Object::getValueOrSetter(PropertyKey id, PropertyAttributes *attrs)
279 if (id.isArrayIndex()) {
280 uint index = id.asArrayIndex();
281 Heap::Object *o = d();
284 uint idx = o->arrayData->mappedIndex(index);
285 if (idx != UINT_MAX) {
286 *attrs = o->arrayData->attributes(index);
287 return { o->arrayData , o->arrayData->values.values + (attrs->isAccessor() ? idx + SetterOffset : idx) };
290 if (o->vtable()->type == Type_StringObject) {
291 if (index <
static_cast<
const Heap::StringObject *>(o)->length()) {
294 *attrs = (Attr_NotWritable|Attr_NotConfigurable);
295 return {
reinterpret_cast<Heap::ArrayData *>(0x1),
nullptr };
301 Heap::Object *o = d();
303 auto idx = o->internalClass->findValueOrSetter(id);
306 return o->writablePropertyData(idx.index);
312 *attrs = Attr_Invalid;
313 return {
nullptr,
nullptr };
316ReturnedValue Object::virtualGet(
const Managed *m, PropertyKey id,
const Value *receiver,
bool *hasProperty)
318 return static_cast<
const Object *>(m)->internalGet(id, receiver, hasProperty);
321bool Object::virtualPut(Managed *m, PropertyKey id,
const Value &value, Value *receiver)
323 return static_cast<Object *>(m)->internalPut(id, value, receiver);
326bool Object::virtualDeleteProperty(Managed *m, PropertyKey id)
328 return static_cast<Object *>(m)->internalDeleteProperty(id);
331PropertyKey ObjectOwnPropertyKeyIterator::next(
const Object *o, Property *pd, PropertyAttributes *attrs)
333 if (arrayIndex != UINT_MAX && o->arrayData()) {
334 SparseArrayNode *arrayNode =
nullptr;
335 if (o->arrayType() == Heap::ArrayData::Sparse) {
336 SparseArray *sparse = o->arrayData()->sparse;
337 arrayNode = arrayIndex ? sparse->lowerBound(arrayIndex) : sparse->begin();
342 while (arrayNode != o->sparseEnd()) {
343 uint k = arrayNode->key();
344 uint pidx = arrayNode->value;
345 Heap::SparseArrayData *sa = o->d()->arrayData.cast<Heap::SparseArrayData>();
346 const Property *p =
reinterpret_cast<
const Property *>(sa->values.data() + pidx);
347 arrayNode = arrayNode->nextNode();
348 PropertyAttributes a = sa->attrs ? sa->attrs[pidx] : Attr_Data;
354 return PropertyKey::fromArrayIndex(k);
356 arrayIndex = UINT_MAX;
359 while (arrayIndex < o->d()->arrayData->values.size) {
360 Heap::SimpleArrayData *sa = o->d()->arrayData.cast<Heap::SimpleArrayData>();
361 const Value &val = sa->data(arrayIndex);
362 PropertyAttributes a = o->arrayData()->attributes(arrayIndex);
363 int index = arrayIndex;
365 if (!val.isEmpty()) {
370 return PropertyKey::fromArrayIndex(index);
373 arrayIndex = UINT_MAX;
377 while (memberIndex < o->internalClass()->size) {
378 PropertyKey n = o->internalClass()->nameMap.at(memberIndex);
380 if (!n.isStringOrSymbol())
383 if (!iterateOverSymbols && n.isSymbol())
385 if (iterateOverSymbols && !n.isSymbol())
388 InternalClassEntry e = o->internalClass()->find(n);
392 pd->value = *o->propertyData(e.index);
393 if (e.attributes.isAccessor())
394 pd->set = *o->propertyData(e.setterIndex);
397 *attrs = e.attributes;
400 if (iterateOverSymbols)
402 iterateOverSymbols =
true;
406 return PropertyKey::invalid();
409OwnPropertyKeyIterator *Object::virtualOwnPropertyKeys(
const Object *o, Value *target)
412 return new ObjectOwnPropertyKeyIterator;
416ReturnedValue Object::internalGet(PropertyKey id,
const Value *receiver,
bool *hasProperty)
const
418 Heap::Object *o = d();
420 if (id.isArrayIndex()) {
421 const uint index = id.asArrayIndex();
423 PropertyAttributes attrs;
424 ScopedProperty pd(scope);
426 if (o->arrayData && o->arrayData->getProperty(index, pd, &attrs)) {
429 return Object::getValue(receiver, pd->value, attrs);
431 if (o->internalClass->vtable->type == Type_StringObject) {
432 ScopedString str(scope,
static_cast<Heap::StringObject *>(o)->getIndex(index));
434 attrs = (Attr_NotWritable|Attr_NotConfigurable);
437 return str.asReturnedValue();
441 if (!o || o->internalClass->vtable->get != Object::virtualGet)
446 auto idx = o->internalClass->findValueOrGetter(id);
450 return Object::getValue(receiver, *o->propertyData(idx.index), idx.attrs);
453 if (!o || o->internalClass->vtable->get != Object::virtualGet)
459 const Value v = Value::fromHeapObject(o);
460 const Object &obj =
static_cast<
const Object &>(v);
461 return obj.get(id, receiver, hasProperty);
465 *hasProperty =
false;
466 return Encode::undefined();
470bool Object::internalPut(PropertyKey id,
const Value &value, Value *receiver)
473 if (scope.hasException())
476 Object *r = receiver->objectValue();
477 if (r && r->d() == d()) {
479 if (d()->internalClass->vtable->getOwnProperty == Object::virtualGetOwnProperty) {
483 PropertyAttributes attrs;
484 PropertyIndex propertyIndex{
nullptr,
nullptr};
486 if (id.isArrayIndex()) {
488 propertyIndex = arrayData()->getValueOrSetter(id.asArrayIndex(), &attrs);
490 auto member = internalClass()->findValueOrSetter(id);
491 if (member.isValid()) {
492 attrs = member.attrs;
493 propertyIndex = d()->writablePropertyData(member.index);
497 if (!propertyIndex.isNull() && !attrs.isAccessor()) {
498 if (!attrs.isWritable())
500 else if (isArrayObject() && id == scope.engine->id_length()->propertyKey()) {
502 uint l = value.asArrayLength(&ok);
504 scope.engine->throwRangeError(value);
507 ok = setArrayLength(l);
511 propertyIndex.set(scope.engine, value);
518 ScopedProperty p(scope);
519 PropertyAttributes attrs;
520 attrs = getOwnProperty(id, p);
521 if (attrs == Attr_Invalid) {
522 ScopedObject p(scope, getPrototypeOf());
524 return p->put(id, value, receiver);
528 if (attrs.isAccessor()) {
529 ScopedFunctionObject setter(scope, p->setter());
532 JSCallArguments jsCallData(scope, 1);
533 jsCallData.args[0] = value;
534 *jsCallData.thisObject = *receiver;
535 setter->call(jsCallData);
536 return !scope.hasException();
540 if (!attrs.isWritable())
544 attrs = r->getOwnProperty(id, p);
546 if (attrs != Attr_Invalid) {
547 if (attrs.isAccessor() || !attrs.isWritable())
550 if (!r->isExtensible())
555 if (r->internalClass()->vtable->defineOwnProperty == virtualDefineOwnProperty) {
557 if (id.isArrayIndex()) {
558 r->arraySet(id.asArrayIndex(), value);
560 ScopedStringOrSymbol s(scope, id.asStringOrSymbol());
561 r->insertMember(s, value);
567 return r->defineOwnProperty(id, p, attrs);
571bool Object::internalDeleteProperty(PropertyKey id)
573 if (internalClass()->engine->hasException)
576 if (id.isArrayIndex()) {
577 uint index = id.asArrayIndex();
578 Scope scope(engine());
579 if (scope.hasException())
582 Scoped<ArrayData> ad(scope, arrayData());
583 if (!ad || ad->vtable()->del(
this, index))
589 auto memberIdx = internalClass()->findValueOrGetter(id);
590 if (memberIdx.isValid()) {
591 if (memberIdx.attrs.isConfigurable()) {
592 Heap::InternalClass::removeMember(
this, id);
601bool Object::internalDefineOwnProperty(ExecutionEngine *engine, uint index,
const InternalClassEntry *memberEntry,
const Property *p, PropertyAttributes attrs)
608 ScopedProperty current(scope);
609 PropertyAttributes cattrs;
611 getProperty(*memberEntry, current);
612 cattrs = memberEntry->attributes;
613 }
else if (arrayData()) {
614 arrayData()->getProperty(index, current, &cattrs);
615 cattrs = arrayData()->attributes(index);
619 if (p->isSubset(attrs, current, cattrs))
623 if (!cattrs.isConfigurable()) {
624 if (attrs.isConfigurable())
626 if (attrs.hasEnumerable() && attrs.isEnumerable() != cattrs.isEnumerable())
631 if (attrs.isGeneric() || current->value.isEmpty())
635 if (cattrs.isData() != attrs.isData()) {
637 if (!cattrs.isConfigurable())
639 if (cattrs.isData()) {
641 cattrs.setType(PropertyAttributes::Accessor);
642 cattrs.clearWritable();
646 Q_ASSERT(arrayData());
647 setArrayAttributes(index, cattrs);
649 current->setGetter(
nullptr);
650 current->setSetter(
nullptr);
653 cattrs.setType(PropertyAttributes::Data);
654 cattrs.setWritable(
false);
657 setArrayAttributes(index, cattrs);
659 current->value = Value::undefinedValue();
661 }
else if (cattrs.isData() && attrs.isData()) {
662 if (!cattrs.isConfigurable() && !cattrs.isWritable()) {
663 if (attrs.isWritable() || !current->value.sameValue(p->value))
667 Q_ASSERT(cattrs.isAccessor() && attrs.isAccessor());
668 if (!cattrs.isConfigurable()) {
669 if (!p->value.isEmpty() && current->value.rawValue() != p->value.rawValue())
671 if (!p->set.isEmpty() && current->set.rawValue() != p->set.rawValue())
678 current->merge(cattrs, p, attrs);
680 PropertyKey key = internalClass()->nameMap.at(memberEntry->index);
681 InternalClassEntry e;
682 Heap::InternalClass::changeMember(
this, key, cattrs, &e);
683 setProperty(e, current);
685 setArrayAttributes(index, cattrs);
686 arrayData()->setProperty(scope.engine, index, current);
691void Object::copyArrayData(Object *other)
693 Q_ASSERT(isArrayObject());
694 Scope scope(engine());
696 if (other->protoHasArray() || ArgumentsObject::isNonStrictArgumentsObject(other) ||
697 (other->arrayType() == Heap::ArrayData::Sparse && other->arrayData()->attrs)) {
698 uint len = other->getLength();
701 ScopedValue v(scope);
702 for (uint i = 0; i < len; ++i) {
703 arraySet(i, (v = other->get(i)));
705 }
else if (!other->arrayData()) {
708 Q_ASSERT(!arrayData() && other->arrayData());
709 ArrayData::realloc(
this,
static_cast<ArrayData::Type>(other->d()->arrayData->type),
710 other->d()->arrayData->values.alloc,
false);
711 if (other->arrayType() == Heap::ArrayData::Sparse) {
712 Heap::ArrayData *od = other->d()->arrayData;
713 Heap::ArrayData *dd = d()->arrayData;
714 dd->sparse =
new SparseArray(*od->sparse);
716 Heap::ArrayData *dd = d()->arrayData;
717 dd->values.size = other->d()->arrayData->values.size;
718 dd->offset = other->d()->arrayData->offset;
721 memcpy(d()->arrayData->values.values, other->d()->arrayData->values.values, other->d()->arrayData->values.alloc*
sizeof(Value));
723 setArrayLengthUnchecked(other->getLength());
726qint64 Object::virtualGetLength(
const Managed *m)
728 Scope scope(
static_cast<
const Object *>(m)->engine());
729 ScopedValue v(scope,
static_cast<Object *>(
const_cast<Managed *>(m))->get(scope.engine->id_length()));
730 return v->toLength();
734ReturnedValue Object::virtualInstanceOf(
const Object *typeObject,
const Value &var)
736 QV4::ExecutionEngine *engine = typeObject->internalClass()->engine;
739 const FunctionObject *function = typeObject->as<FunctionObject>();
741 return engine->throwTypeError();
743 return checkedInstanceOf(engine, function, var);
746ReturnedValue Object::virtualResolveLookupGetter(
const Object *object, ExecutionEngine *engine, Lookup *lookup)
749 Q_ASSERT(engine->isInitialized);
751 Heap::Object *obj = object->d();
752 PropertyKey name = engine->identifierTable->asPropertyKey(engine->currentStackFrame->v4Function->compilationUnit->runtimeStrings[lookup->nameIndex]);
753 if (object->as<QV4::ProxyObject>()) {
756 lookup->call = Lookup::Call::GetterQObjectPropertyFallback;
757 return lookup->getter(engine, *object);
759 if (name.isArrayIndex()) {
760 lookup->indexedLookup.index = name.asArrayIndex();
761 lookup->call = Lookup::Call::GetterIndexed;
762 return lookup->getter(engine, *object);
765 auto index = obj->internalClass->findValueOrGetter(name);
766 if (index.isValid()) {
767 PropertyAttributes attrs = index.attrs;
768 uint nInline = obj->vtable()->nInlineProperties;
769 if (attrs.isData()) {
770 if (index.index < obj->vtable()->nInlineProperties) {
771 index.index += obj->vtable()->inlinePropertyOffset;
772 lookup->call = Lookup::Call::Getter0Inline;
774 index.index -= nInline;
775 lookup->call = Lookup::Call::Getter0MemberData;
778 lookup->call = Lookup::Call::GetterAccessor;
780 lookup->objectLookup.ic.set(engine, obj->internalClass.get());
781 lookup->objectLookup.offset = index.index;
782 return lookup->getter(engine, *object);
785 lookup->protoLookup.protoId = obj->internalClass->protoId;
786 lookup->resolveProtoGetter(name, obj->prototype());
787 return lookup->getter(engine, *object);
790bool Object::virtualResolveLookupSetter(Object *object, ExecutionEngine *engine, Lookup *lookup,
const Value &value)
793 Q_ASSERT(engine->isInitialized);
796 ScopedString name(scope, scope.engine->currentStackFrame->v4Function->compilationUnit->runtimeStrings[lookup->nameIndex]);
798 Heap::InternalClass *c = object->internalClass();
799 PropertyKey key = name->toPropertyKey();
800 auto idx = c->findValueOrSetter(key);
802 if (object->isArrayObject() && idx.index == Heap::ArrayObject::LengthPropertyIndex) {
803 Q_ASSERT(!idx.attrs.isAccessor());
804 lookup->call = Lookup::Call::SetterArrayLength;
805 return lookup->setter(engine, *object, value);
806 }
else if (idx.attrs.isData() && idx.attrs.isWritable()) {
807 lookup->objectLookup.ic.set(engine, object->internalClass());
808 lookup->objectLookup.index = idx.index;
809 const auto nInline = object->d()->vtable()->nInlineProperties;
810 if (idx.index < nInline) {
811 lookup->call = Lookup::Call::Setter0Inline;
812 lookup->objectLookup.offset = idx.index + object->d()->vtable()->inlinePropertyOffset;
814 lookup->call = Lookup::Call::Setter0MemberData;
815 lookup->objectLookup.offset = idx.index - nInline;
817 return lookup->setter(engine, *object, value);
820 lookup->call = Lookup::Call::SetterQObjectPropertyFallback;
822 return lookup->setter(engine, *object, value);
825 lookup->insertionLookup.protoId = c->protoId;
826 if (!object->put(key, value)) {
827 lookup->call = Lookup::Call::SetterQObjectPropertyFallback;
831 if (object->internalClass() == c) {
833 lookup->call = Lookup::Call::SetterQObjectPropertyFallback;
836 idx = object->internalClass()->findValueOrSetter(key);
837 if (!idx.isValid() || idx.attrs.isAccessor()) {
838 lookup->call = Lookup::Call::SetterQObjectPropertyFallback;
841 lookup->insertionLookup.newClass.set(engine, object->internalClass());
842 lookup->insertionLookup.offset = idx.index;
843 lookup->call = Lookup::Call::SetterInsert;
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863int Object::virtualMetacall(Object *object, QMetaObject::Call call,
int index,
void **a)
872ReturnedValue Object::checkedInstanceOf(ExecutionEngine *engine,
const FunctionObject *f,
const Value &var)
875 if (f->isBoundFunction()) {
876 ScopedValue v(scope,
static_cast<
const BoundFunction *>(f)->target());
877 f = v->as<FunctionObject>();
881 const Object *lhs = var.as<Object>();
883 return Encode(
false);
886 Value p = Value::fromReturnedValue(f->protoProperty());
887 const Object *o = p.objectValue();
889 return f->engine()->throwTypeError();
891 Heap::Object *v = lhs->d();
903 else if (o->d() == v)
907 return Encode(
false);
910bool Object::virtualHasProperty(
const Managed *m, PropertyKey id)
912 Scope scope(m->engine());
913 ScopedObject o(scope, m);
914 ScopedProperty p(scope);
916 if (o->getOwnProperty(id, p) != Attr_Invalid)
919 o = o->getPrototypeOf();
921 return o->hasProperty(id);
926PropertyAttributes Object::virtualGetOwnProperty(
const Managed *m, PropertyKey id, Property *p)
928 PropertyAttributes attrs;
929 const Object *o =
static_cast<
const Object *>(m);
930 if (id.isArrayIndex()) {
931 uint index = id.asArrayIndex();
932 if (o->arrayData()) {
933 if (o->arrayData()->getProperty(index, p, &attrs))
937 Q_ASSERT(id.asStringOrSymbol());
939 auto member = o->internalClass()->find(id);
940 if (member.isValid()) {
941 attrs = member.attributes;
943 p->value = *o->propertyData(member.index);
944 if (attrs.isAccessor())
945 p->set = *o->propertyData(member.setterIndex);
954bool Object::virtualDefineOwnProperty(Managed *m, PropertyKey id,
const Property *p, PropertyAttributes attrs)
956 Object *o =
static_cast<Object *>(m);
959 if (id.isArrayIndex()) {
960 uint index = id.asArrayIndex();
962 bool hasProperty =
false;
964 if (o->arrayData()) {
965 hasProperty = o->arrayData()->mappedIndex(index) != UINT_MAX;
966 if (!hasProperty && o->isStringObject())
967 hasProperty = (index <
static_cast<StringObject *>(o)->length());
971 if (!o->isExtensible())
974 ScopedProperty pp(scope);
976 pp->fullyPopulated(&attrs);
977 if (attrs == Attr_Data) {
978 ScopedValue v(scope, pp->value);
979 o->arraySet(index, v);
981 o->arraySet(index, pp, attrs);
986 return o->internalDefineOwnProperty(scope.engine, index,
nullptr, p, attrs);
989 Scoped<InternalClass> ic(scope, o->internalClass());
990 auto memberIndex = ic->d()->find(id);
992 if (!memberIndex.isValid()) {
993 if (!o->isExtensible())
997 if (ic->d()->isLocked()) {
998 while (Heap::Object *prototype = ic->d()->prototype) {
999 ic = prototype->internalClass;
1000 const auto entry = ic->d()->find(id);
1001 if (entry.isValid()) {
1002 if (entry.attributes.isConfigurable())
1004 qCWarning(lcJavaScriptGlobals).noquote()
1005 << QStringLiteral(
"You cannot shadow the locked property "
1006 "'%1' in QML.").arg(id.toQString());
1012 Scoped<StringOrSymbol> name(scope, id.asStringOrSymbol());
1013 ScopedProperty pd(scope);
1015 pd->fullyPopulated(&attrs);
1016 o->insertMember(name, pd, attrs);
1020 return o->internalDefineOwnProperty(scope.engine, UINT_MAX, &memberIndex, p, attrs);
1023bool Object::virtualIsExtensible(
const Managed *m)
1025 return m->d()->internalClass->isExtensible();
1028bool Object::virtualPreventExtensions(Managed *m)
1030 Q_ASSERT(m->isObject());
1031 Object *o =
static_cast<Object *>(m);
1032 o->setInternalClass(o->internalClass()->nonExtensible());
1036Heap::Object *Object::virtualGetPrototypeOf(
const Managed *m)
1038 return m->internalClass()->prototype;
1041bool Object::virtualSetPrototypeOf(Managed *m,
const Object *proto)
1043 Q_ASSERT(m->isObject());
1044 Object *o =
static_cast<Object *>(m);
1045 Heap::InternalClass *ic = o->internalClass();
1046 Heap::Object *current = ic->prototype;
1047 Heap::Object *protod = proto ? proto->d() :
nullptr;
1048 if (current == protod)
1050 if (!ic->isExtensible() || ic->isLocked())
1052 Heap::Object *p = protod;
1056 if (p->vtable()->getPrototypeOf != Object::staticVTable()->getPrototypeOf)
1060 o->setInternalClass(ic->changePrototype(protod));
1064bool Object::setArrayLength(uint newLen)
1066 Q_ASSERT(isArrayObject());
1067 if (!internalClass()->propertyData[Heap::ArrayObject::LengthPropertyIndex].isWritable())
1069 uint oldLen = getLength();
1071 if (newLen < oldLen) {
1073 uint l = arrayData()->vtable()->truncate(
this, newLen);
1079 if (newLen >= 0x100000)
1082 ArrayData::realloc(
this, arrayType(), newLen,
false);
1084 setArrayLengthUnchecked(newLen);
1088void Object::initSparseArray()
1090 if (arrayType() == Heap::ArrayData::Sparse)
1093 ArrayData::realloc(
this, Heap::ArrayData::Sparse, 0,
false);
1096bool Object::isConcatSpreadable()
const
1099 ScopedValue spreadable(scope, get(scope.engine->symbol_isConcatSpreadable()));
1100 if (!spreadable->isUndefined())
1101 return spreadable->toBoolean();
1105bool Object::isArray()
const
1107 if (isArrayObject())
1109 if (vtable() == ProxyObject::staticVTable()) {
1110 const ProxyObject *p =
static_cast<
const ProxyObject *>(
this);
1112 if (!p->d()->handler) {
1113 scope.engine->throwTypeError();
1116 ScopedObject o(scope, p->d()->target);
1117 return o->isArray();
1122const FunctionObject *Object::speciesConstructor(Scope &scope,
const FunctionObject *defaultConstructor)
const
1124 ScopedValue C(scope, get(scope.engine->id_constructor()));
1125 if (C->isUndefined())
1126 return defaultConstructor;
1127 const Object *c = C->objectValue();
1129 scope.engine->throwTypeError();
1132 ScopedValue S(scope, c->get(scope.engine->symbol_species()));
1133 if (S->isNullOrUndefined())
1134 return defaultConstructor;
1135 const FunctionObject *f = S->as<FunctionObject>();
1136 if (!f || !f->isConstructor()) {
1137 scope.engine->throwTypeError();
1140 Q_ASSERT(f->isFunctionObject());
1141 return static_cast<
const FunctionObject *>(f);
1144bool Object::setProtoFromNewTarget(
const Value *newTarget)
1146 if (!newTarget || newTarget->isUndefined())
1149 Q_ASSERT(newTarget->isFunctionObject());
1151 ScopedObject proto(scope,
static_cast<
const FunctionObject *>(newTarget)->protoProperty());
1153 setPrototypeOf(proto);
1162void Heap::ArrayObject::init(
const QStringList &list)
1166 Scope scope(internalClass->engine);
1167 ScopedObject a(scope,
this);
1173 int len = list.size();
1174 a->arrayReserve(len);
1175 ScopedValue v(scope);
1176 for (
int ii = 0; ii < len; ++ii)
1177 a->arrayPut(ii, (v = scope.engine->newString(list.at(ii))));
1178 a->setArrayLengthUnchecked(len);
1181qint64 ArrayObject::virtualGetLength(
const Managed *m)
1183 const ArrayObject *a =
static_cast<
const ArrayObject *>(m);
1184 return a->propertyData(Heap::ArrayObject::LengthPropertyIndex)->toLength();
1187QStringList ArrayObject::toQStringList()
const
1191 QV4::ExecutionEngine *engine = internalClass()->engine;
1192 Scope scope(engine);
1193 ScopedValue v(scope);
1195 uint length = getLength();
1196 result.reserve(length);
1197 for (uint i = 0; i < length; ++i) {
1198 v =
const_cast<ArrayObject *>(
this)->get(i);
1199 result.append(v->toQStringNoThrow());
1204bool ArrayObject::virtualDefineOwnProperty(Managed *m, PropertyKey id,
const Property *p, PropertyAttributes attrs)
1206 Q_ASSERT(m->isArrayObject());
1207 ArrayObject *a =
static_cast<ArrayObject *>(m);
1209 if (id.isArrayIndex()) {
1210 uint index = id.asArrayIndex();
1211 uint len = a->getLength();
1212 if (index >= len && !a->internalClass()->propertyData[Heap::ArrayObject::LengthPropertyIndex].isWritable())
1215 bool succeeded = Object::virtualDefineOwnProperty(m, id, p, attrs);
1220 a->setArrayLengthUnchecked(index + 1);
1225 ExecutionEngine *engine = m->engine();
1226 if (id == engine->id_length()->propertyKey()) {
1227 Scope scope(engine);
1228 Q_ASSERT(a->internalClass()->verifyIndex(engine->id_length()->propertyKey(), Heap::ArrayObject::LengthPropertyIndex));
1229 ScopedProperty lp(scope);
1230 InternalClassEntry e = a->internalClass()->find(scope.engine->id_length()->propertyKey());
1231 a->getProperty(e, lp);
1232 if (attrs.isEmpty() || p->isSubset(attrs, lp, e.attributes))
1234 if (!e.attributes.isWritable() || attrs.type() == PropertyAttributes::Accessor || attrs.isConfigurable() || attrs.isEnumerable())
1236 bool succeeded =
true;
1237 if (attrs.type() == PropertyAttributes::Data) {
1239 uint l = p->value.asArrayLength(&ok);
1241 ScopedValue v(scope, p->value);
1242 engine->throwRangeError(v);
1245 succeeded = a->setArrayLength(l);
1247 if (attrs.hasWritable() && !attrs.isWritable()) {
1248 e.attributes.setWritable(
false);
1249 Heap::InternalClass::changeMember(a, engine->id_length()->propertyKey(), e.attributes);
1255 return Object::virtualDefineOwnProperty(m, id, p, attrs);
Q_STATIC_LOGGING_CATEGORY(lcAccessibilityCore, "qt.accessibility.core")
DEFINE_OBJECT_VTABLE(ArrayObject)