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 ****************************************************************************/
36 #include "qv4managed_p.h"
37 #include "qv4memberdata_p.h"
38 #include "qv4arraydata_p.h"
39 #include "qv4engine_p.h"
40 #include "qv4scopedvalue_p.h"
41 #include "qv4value_p.h"
49 struct Object : Base {
50 inline Object(ExecutionEngine *engine);
51 Object(InternalClass *internal, QV4::Object *prototype);
53 const Property *propertyAt(uint index) const { return reinterpret_cast<const Property *>(memberData->data + index); }
54 Property *propertyAt(uint index) { return reinterpret_cast<Property *>(memberData->data + index); }
56 InternalClass *internalClass;
57 Pointer<Object> prototype;
58 Pointer<MemberData> memberData;
59 Pointer<ArrayData> arrayData;
64 #define V4_OBJECT(superClass) \
67 typedef superClass SuperClass; \
68 static const QV4::ObjectVTable static_vtbl; \
69 static inline const QV4::VTable *staticVTable() { return &static_vtbl.vTable; } \
70 V4_MANAGED_SIZE_TEST \
71 Data *d() const { return static_cast<Data *>(m()); }
73 #define V4_OBJECT2(DataClass, superClass) \
76 typedef QV4::Heap::DataClass Data; \
77 typedef superClass SuperClass; \
78 static const QV4::ObjectVTable static_vtbl; \
79 static inline const QV4::VTable *staticVTable() { return &static_vtbl.vTable; } \
80 V4_MANAGED_SIZE_TEST \
81 QV4::Heap::DataClass *d() const { return static_cast<QV4::Heap::DataClass *>(m()); }
86 ReturnedValue (*call)(const Managed *, CallData *data);
87 ReturnedValue (*construct)(const Managed *, CallData *data);
88 ReturnedValue (*get)(const Managed *, String *name, bool *hasProperty);
89 ReturnedValue (*getIndexed)(const Managed *, uint index, bool *hasProperty);
90 void (*put)(Managed *, String *name, const Value &value);
91 void (*putIndexed)(Managed *, uint index, const Value &value);
92 PropertyAttributes (*query)(const Managed *, String *name);
93 PropertyAttributes (*queryIndexed)(const Managed *, uint index);
94 bool (*deleteProperty)(Managed *m, String *name);
95 bool (*deleteIndexedProperty)(Managed *m, uint index);
96 ReturnedValue (*getLookup)(const Managed *m, Lookup *l);
97 void (*setLookup)(Managed *m, Lookup *l, const Value &v);
98 uint (*getLength)(const Managed *m);
99 void (*advanceIterator)(Managed *m, ObjectIterator *it, Value *name, uint *index, Property *p, PropertyAttributes *attributes);
102 #define DEFINE_OBJECT_VTABLE(classname) \
103 const QV4::ObjectVTable classname::static_vtbl = \
105 DEFINE_MANAGED_VTABLE_INT(classname, &classname::SuperClass::static_vtbl == &Object::static_vtbl ? 0 : &classname::SuperClass::static_vtbl.vTable), \
115 deleteIndexedProperty, \
124 struct Q_QML_EXPORT Object: Managed {
125 V4_OBJECT2(Object, Object)
126 Q_MANAGED_TYPE(Object)
132 InternalClass *internalClass() const { return d()->internalClass; }
133 void setInternalClass(InternalClass *ic) { d()->internalClass = ic; }
135 Heap::MemberData *memberData() { return d()->memberData; }
136 const Heap::MemberData *memberData() const { return d()->memberData; }
137 Heap::ArrayData *arrayData() const { return d()->arrayData; }
138 void setArrayData(ArrayData *a) { d()->arrayData = a->d(); }
140 const Property *propertyAt(uint index) const { return d()->propertyAt(index); }
141 Property *propertyAt(uint index) { return d()->propertyAt(index); }
143 const ObjectVTable *vtable() const { return reinterpret_cast<const ObjectVTable *>(d()->vtable()); }
144 Heap::Object *prototype() const { return d()->prototype; }
145 bool setPrototype(Object *proto);
147 void getOwnProperty(String *name, PropertyAttributes *attrs, Property *p = 0);
148 void getOwnProperty(uint index, PropertyAttributes *attrs, Property *p = 0);
150 Property *__getPropertyDescriptor__(String *name, PropertyAttributes *attrs) const;
151 Property *__getPropertyDescriptor__(uint index, PropertyAttributes *attrs) const;
153 bool hasProperty(String *name) const;
154 bool hasProperty(uint index) const;
156 bool hasOwnProperty(String *name) const;
157 bool hasOwnProperty(uint index) const;
159 bool __defineOwnProperty__(ExecutionEngine *engine, uint index, String *member, const Property *p, PropertyAttributes attrs);
160 bool __defineOwnProperty__(ExecutionEngine *engine, String *name, const Property *p, PropertyAttributes attrs);
161 bool __defineOwnProperty__(ExecutionEngine *engine, uint index, const Property *p, PropertyAttributes attrs);
162 bool __defineOwnProperty__(ExecutionEngine *engine, const QString &name, const Property *p, PropertyAttributes attrs);
163 bool defineOwnProperty2(ExecutionEngine *engine, uint index, const Property *p, PropertyAttributes attrs);
168 void put(ExecutionEngine *engine, const QString &name, const Value &value);
170 static ReturnedValue getValue(const Value &thisObject, const Property *p, PropertyAttributes attrs);
171 ReturnedValue getValue(const Property *p, PropertyAttributes attrs) const {
172 Scope scope(this->engine());
173 ScopedValue t(scope, const_cast<Object *>(this));
174 return getValue(t, p, attrs);
177 void putValue(Property *pd, PropertyAttributes attrs, const Value &value);
179 /* The spec default: Writable: true, Enumerable: false, Configurable: true */
180 void defineDefaultProperty(String *name, const Value &value) {
181 insertMember(name, value, Attr_Data|Attr_NotEnumerable);
183 void defineDefaultProperty(const QString &name, const Value &value);
184 void defineDefaultProperty(const QString &name, ReturnedValue (*code)(CallContext *), int argumentCount = 0);
185 void defineDefaultProperty(String *name, ReturnedValue (*code)(CallContext *), int argumentCount = 0);
186 void defineAccessorProperty(const QString &name, ReturnedValue (*getter)(CallContext *), ReturnedValue (*setter)(CallContext *));
187 void defineAccessorProperty(String *name, ReturnedValue (*getter)(CallContext *), ReturnedValue (*setter)(CallContext *));
188 /* Fixed: Writable: false, Enumerable: false, Configurable: false */
189 void defineReadonlyProperty(const QString &name, const Value &value);
190 void defineReadonlyProperty(String *name, const Value &value);
192 void ensureMemberIndex(QV4::ExecutionEngine *e, uint idx) {
193 d()->memberData = MemberData::reallocate(e, d()->memberData, idx);
196 void insertMember(String *s, const Value &v, PropertyAttributes attributes = Attr_Data) {
197 Scope scope(engine());
198 ScopedProperty p(scope);
200 insertMember(s, p, attributes);
202 void insertMember(String *s, const Property *p, PropertyAttributes attributes);
204 inline ExecutionEngine *engine() const { return internalClass()->engine; }
206 bool isExtensible() const { return d()->internalClass->extensible; }
211 void copyArrayData(Object *other);
213 bool setArrayLength(uint newLen);
214 void setArrayLengthUnchecked(uint l);
216 void arraySet(uint index, const Property *p, PropertyAttributes attributes = Attr_Data);
217 void arraySet(uint index, const Value &value);
219 bool arrayPut(uint index, const Value &value) {
220 return arrayData()->vtable()->put(this, index, value);
222 bool arrayPut(uint index, const Value *values, uint n) {
223 return arrayData()->vtable()->putArray(this, index, values, n);
225 void setArrayAttributes(uint i, PropertyAttributes a) {
226 Q_ASSERT(arrayData());
227 if (d()->arrayData->attrs || a != Attr_Data) {
228 ArrayData::ensureAttributes(this);
230 arrayData()->vtable()->setAttribute(this, i, a);
234 void push_back(const Value &v);
236 ArrayData::Type arrayType() const {
237 return arrayData() ? d()->arrayData->type : Heap::ArrayData::Simple;
240 void setArrayType(ArrayData::Type t) {
241 Q_ASSERT(t != Heap::ArrayData::Simple && t != Heap::ArrayData::Sparse);
243 d()->arrayData->type = t;
246 inline void arrayReserve(uint n) {
247 ArrayData::realloc(this, Heap::ArrayData::Simple, n, false);
252 ArrayData::realloc(this, Heap::ArrayData::Simple, 0, false);
253 #ifdef CHECK_SPARSE_ARRAYS
258 void initSparseArray();
259 SparseArrayNode *sparseBegin() { return arrayType() == Heap::ArrayData::Sparse ? d()->arrayData->sparse->begin() : 0; }
260 SparseArrayNode *sparseEnd() { return arrayType() == Heap::ArrayData::Sparse ? d()->arrayData->sparse->end() : 0; }
262 inline bool protoHasArray() {
263 Scope scope(engine());
264 ScopedObject p(scope, this);
266 while ((p = p->prototype()))
272 void ensureMemberIndex(uint idx);
274 inline ReturnedValue get(String *name, bool *hasProperty = 0) const
275 { return vtable()->get(this, name, hasProperty); }
276 inline ReturnedValue getIndexed(uint idx, bool *hasProperty = 0) const
277 { return vtable()->getIndexed(this, idx, hasProperty); }
278 inline void put(String *name, const Value &v)
279 { vtable()->put(this, name, v); }
280 inline void putIndexed(uint idx, const Value &v)
281 { vtable()->putIndexed(this, idx, v); }
282 PropertyAttributes query(String *name) const
283 { return vtable()->query(this, name); }
284 PropertyAttributes queryIndexed(uint index) const
285 { return vtable()->queryIndexed(this, index); }
286 bool deleteProperty(String *name)
287 { return vtable()->deleteProperty(this, name); }
288 bool deleteIndexedProperty(uint index)
289 { return vtable()->deleteIndexedProperty(this, index); }
290 ReturnedValue getLookup(Lookup *l) const
291 { return vtable()->getLookup(this, l); }
292 void setLookup(Lookup *l, const Value &v)
293 { vtable()->setLookup(this, l, v); }
294 void advanceIterator(ObjectIterator *it, Value *name, uint *index, Property *p, PropertyAttributes *attributes)
295 { vtable()->advanceIterator(this, it, name, index, p, attributes); }
296 uint getLength() const { return vtable()->getLength(this); }
298 inline ReturnedValue construct(CallData *d) const
299 { return vtable()->construct(this, d); }
300 inline ReturnedValue call(CallData *d) const
301 { return vtable()->call(this, d); }
303 static void markObjects(Heap::Base *that, ExecutionEngine *e);
304 static ReturnedValue construct(const Managed *m, CallData *);
305 static ReturnedValue call(const Managed *m, CallData *);
306 static ReturnedValue get(const Managed *m, String *name, bool *hasProperty);
307 static ReturnedValue getIndexed(const Managed *m, uint index, bool *hasProperty);
308 static void put(Managed *m, String *name, const Value &value);
309 static void putIndexed(Managed *m, uint index, const Value &value);
310 static PropertyAttributes query(const Managed *m, String *name);
311 static PropertyAttributes queryIndexed(const Managed *m, uint index);
312 static bool deleteProperty(Managed *m, String *name);
313 static bool deleteIndexedProperty(Managed *m, uint index);
314 static ReturnedValue getLookup(const Managed *m, Lookup *l);
315 static void setLookup(Managed *m, Lookup *l, const Value &v);
316 static void advanceIterator(Managed *m, ObjectIterator *it, Value *name, uint *index, Property *p, PropertyAttributes *attributes);
317 static uint getLength(const Managed *m);
320 ReturnedValue internalGet(String *name, bool *hasProperty) const;
321 ReturnedValue internalGetIndexed(uint index, bool *hasProperty) const;
322 void internalPut(String *name, const Value &value);
323 void internalPutIndexed(uint index, const Value &value);
324 bool internalDeleteProperty(String *name);
325 bool internalDeleteIndexedProperty(uint index);
327 friend struct ObjectIterator;
328 friend struct ObjectPrototype;
333 inline Object::Object(ExecutionEngine *engine)
334 : internalClass(engine->emptyClass),
335 prototype(static_cast<Object *>(engine->objectPrototype()->m()))
339 struct BooleanObject : Object {
340 BooleanObject(InternalClass *ic, QV4::Object *prototype)
341 : Object(ic, prototype),
346 BooleanObject(ExecutionEngine *engine, bool b)
347 : Object(engine->emptyClass, engine->booleanPrototype()),
354 struct NumberObject : Object {
355 NumberObject(InternalClass *ic, QV4::Object *prototype)
356 : Object(ic, prototype),
361 NumberObject(ExecutionEngine *engine, double val)
362 : Object(engine->emptyClass, engine->numberPrototype()),
369 struct ArrayObject : Object {
371 LengthPropertyIndex = 0
374 ArrayObject(ExecutionEngine *engine)
375 : Heap::Object(engine->arrayClass, engine->arrayPrototype())
377 ArrayObject(ExecutionEngine *engine, const QStringList &list);
378 ArrayObject(InternalClass *ic, QV4::Object *prototype)
379 : Heap::Object(ic, prototype)
382 { memberData->data[LengthPropertyIndex] = Primitive::fromInt32(0); }
387 struct BooleanObject: Object {
388 V4_OBJECT2(BooleanObject, Object)
389 Q_MANAGED_TYPE(BooleanObject)
391 bool value() const { return d()->b; }
395 struct NumberObject: Object {
396 V4_OBJECT2(NumberObject, Object)
397 Q_MANAGED_TYPE(NumberObject)
399 double value() const { return d()->value; }
402 struct ArrayObject: Object {
403 V4_OBJECT2(ArrayObject, Object)
404 Q_MANAGED_TYPE(ArrayObject)
406 void init(ExecutionEngine *engine);
408 static ReturnedValue getLookup(const Managed *m, Lookup *l);
409 using Object::getLength;
410 static uint getLength(const Managed *m);
412 QStringList toQStringList() const;
415 inline void Object::setArrayLengthUnchecked(uint l)
418 memberData()->data[Heap::ArrayObject::LengthPropertyIndex] = Primitive::fromUInt32(l);
421 inline void Object::push_back(const Value &v)
425 uint idx = getLength();
426 arrayReserve(idx + 1);
428 setArrayLengthUnchecked(idx + 1);
431 inline void Object::arraySet(uint index, const Property *p, PropertyAttributes attributes)
435 if (attributes.isAccessor() || (index > 0x1000 && index > 2*d()->arrayData->alloc)) {
438 arrayData()->vtable()->reallocate(this, index + 1, false);
440 setArrayAttributes(index, attributes);
441 Property *pd = ArrayData::insert(this, index, attributes.isAccessor());
442 pd->value = p->value;
443 if (attributes.isAccessor())
445 if (isArrayObject() && index >= getLength())
446 setArrayLengthUnchecked(index + 1);
450 inline void Object::arraySet(uint index, const Value &value)
453 if (index > 0x1000 && index > 2*d()->arrayData->alloc) {
456 Property *pd = ArrayData::insert(this, index);
458 if (isArrayObject() && index >= getLength())
459 setArrayLengthUnchecked(index + 1);
464 inline const ArrayObject *Value::as() const {
465 return isManaged() && m() && m()->vtable()->type == Managed::Type_ArrayObject ? static_cast<const ArrayObject *>(this) : 0;
470 inline ReturnedValue value_convert<Object>(ExecutionEngine *e, const Value &v)
472 return v.toObject(e)->asReturnedValue();
480 #endif // QMLJS_OBJECTS_H