1 | /**************************************************************************** |
2 | ** |
3 | ** Copyright (C) 2016 The Qt Company Ltd. |
4 | ** Contact: https://www.qt.io/licensing/ |
5 | ** |
6 | ** This file is part of the QtQml module of the Qt Toolkit. |
7 | ** |
8 | ** $QT_BEGIN_LICENSE:LGPL$ |
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 https://www.qt.io/terms-conditions. For further |
15 | ** information use the contact form at https://www.qt.io/contact-us. |
16 | ** |
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 3 as published by the Free Software |
20 | ** Foundation and appearing in the file LICENSE.LGPL3 included in the |
21 | ** packaging of this file. Please review the following information to |
22 | ** ensure the GNU Lesser General Public License version 3 requirements |
23 | ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. |
24 | ** |
25 | ** GNU General Public License Usage |
26 | ** Alternatively, this file may be used under the terms of the GNU |
27 | ** General Public License version 2.0 or (at your option) the GNU General |
28 | ** Public license version 3 or any later version approved by the KDE Free |
29 | ** Qt Foundation. The licenses are as published by the Free Software |
30 | ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 |
31 | ** included in the packaging of this file. Please review the following |
32 | ** information to ensure the GNU General Public License requirements will |
33 | ** be met: https://www.gnu.org/licenses/gpl-2.0.html and |
34 | ** https://www.gnu.org/licenses/gpl-3.0.html. |
35 | ** |
36 | ** $QT_END_LICENSE$ |
37 | ** |
38 | ****************************************************************************/ |
39 | #ifndef QV4_OBJECT_H |
40 | #define QV4_OBJECT_H |
41 | |
42 | // |
43 | // W A R N I N G |
44 | // ------------- |
45 | // |
46 | // This file is not part of the Qt API. It exists purely as an |
47 | // implementation detail. This header file may change from version to |
48 | // version without notice, or even be removed. |
49 | // |
50 | // We mean it. |
51 | // |
52 | |
53 | #include "qv4managed_p.h" |
54 | #include "qv4memberdata_p.h" |
55 | #include "qv4arraydata_p.h" |
56 | #include "qv4engine_p.h" |
57 | #include "qv4scopedvalue_p.h" |
58 | #include "qv4value_p.h" |
59 | #include "qv4internalclass_p.h" |
60 | #include "qv4string_p.h" |
61 | |
62 | QT_BEGIN_NAMESPACE |
63 | |
64 | |
65 | namespace QV4 { |
66 | |
67 | namespace Heap { |
68 | |
69 | #define ObjectMembers(class, Member) \ |
70 | Member(class, Pointer, MemberData *, memberData) \ |
71 | Member(class, Pointer, ArrayData *, arrayData) |
72 | |
73 | DECLARE_EXPORTED_HEAP_OBJECT(Object, Base) { |
74 | static void markObjects(Heap::Base *base, MarkStack *stack); |
75 | void init() { Base::init(); } |
76 | |
77 | const VTable *vtable() const { |
78 | return internalClass->vtable; |
79 | } |
80 | |
81 | const Value *inlinePropertyDataWithOffset(uint indexWithOffset) const { |
82 | Q_ASSERT(indexWithOffset >= vtable()->inlinePropertyOffset && indexWithOffset < uint(vtable()->inlinePropertyOffset + vtable()->nInlineProperties)); |
83 | return reinterpret_cast<const Value *>(this) + indexWithOffset; |
84 | } |
85 | const Value *inlinePropertyData(uint index) const { |
86 | Q_ASSERT(index < vtable()->nInlineProperties); |
87 | return reinterpret_cast<const Value *>(this) + vtable()->inlinePropertyOffset + index; |
88 | } |
89 | void setInlinePropertyWithOffset(ExecutionEngine *e, uint indexWithOffset, Value v) { |
90 | Q_ASSERT(indexWithOffset >= vtable()->inlinePropertyOffset && indexWithOffset < uint(vtable()->inlinePropertyOffset + vtable()->nInlineProperties)); |
91 | Value *prop = reinterpret_cast<Value *>(this) + indexWithOffset; |
92 | WriteBarrier::write(engine: e, base: this, slot: prop->data_ptr(), value: v.asReturnedValue()); |
93 | } |
94 | void setInlinePropertyWithOffset(ExecutionEngine *e, uint indexWithOffset, Heap::Base *b) { |
95 | Q_ASSERT(indexWithOffset >= vtable()->inlinePropertyOffset && indexWithOffset < uint(vtable()->inlinePropertyOffset + vtable()->nInlineProperties)); |
96 | Value *prop = reinterpret_cast<Value *>(this) + indexWithOffset; |
97 | WriteBarrier::write(engine: e, base: this, slot: prop->data_ptr(), value: Value::fromHeapObject(m: b).asReturnedValue()); |
98 | } |
99 | |
100 | PropertyIndex writablePropertyData(uint index) { |
101 | uint nInline = vtable()->nInlineProperties; |
102 | if (index < nInline) |
103 | return PropertyIndex{ .base: this, .slot: reinterpret_cast<Value *>(this) + vtable()->inlinePropertyOffset + index}; |
104 | index -= nInline; |
105 | return PropertyIndex{ .base: memberData, .slot: memberData->values.values + index }; |
106 | } |
107 | |
108 | const Value *propertyData(uint index) const { |
109 | uint nInline = vtable()->nInlineProperties; |
110 | if (index < nInline) |
111 | return reinterpret_cast<const Value *>(this) + vtable()->inlinePropertyOffset + index; |
112 | index -= nInline; |
113 | return memberData->values.data() + index; |
114 | } |
115 | void setProperty(ExecutionEngine *e, uint index, Value v) { |
116 | uint nInline = vtable()->nInlineProperties; |
117 | if (index < nInline) { |
118 | setInlinePropertyWithOffset(e, indexWithOffset: index + vtable()->inlinePropertyOffset, v); |
119 | return; |
120 | } |
121 | index -= nInline; |
122 | memberData->values.set(e, index, v); |
123 | } |
124 | void setProperty(ExecutionEngine *e, uint index, Heap::Base *b) { |
125 | uint nInline = vtable()->nInlineProperties; |
126 | if (index < nInline) { |
127 | setInlinePropertyWithOffset(e, indexWithOffset: index + vtable()->inlinePropertyOffset, b); |
128 | return; |
129 | } |
130 | index -= nInline; |
131 | memberData->values.set(e, index, b); |
132 | } |
133 | |
134 | void setUsedAsProto(); |
135 | |
136 | Heap::Object *prototype() const { return internalClass->prototype; } |
137 | }; |
138 | |
139 | } |
140 | |
141 | struct Q_QML_EXPORT Object: Managed { |
142 | V4_OBJECT2(Object, Object) |
143 | Q_MANAGED_TYPE(Object) |
144 | V4_INTERNALCLASS(Object) |
145 | V4_PROTOTYPE(objectPrototype) |
146 | |
147 | enum { NInlineProperties = 2 }; |
148 | |
149 | enum { |
150 | IsObject = true, |
151 | GetterOffset = 0, |
152 | SetterOffset = 1 |
153 | }; |
154 | |
155 | void setInternalClass(Heap::InternalClass *ic); |
156 | |
157 | const Value *propertyData(uint index) const { return d()->propertyData(index); } |
158 | |
159 | Heap::ArrayData *arrayData() const { return d()->arrayData; } |
160 | void setArrayData(ArrayData *a) { d()->arrayData.set(e: engine(), newVal: a ? a->d() : nullptr); } |
161 | |
162 | void getProperty(const InternalClassEntry &entry, Property *p) const; |
163 | void setProperty(const InternalClassEntry &entry, const Property *p); |
164 | void setProperty(uint index, Value v) const { d()->setProperty(e: engine(), index, v); } |
165 | void setProperty(uint index, Heap::Base *b) const { d()->setProperty(e: engine(), index, b); } |
166 | void setProperty(ExecutionEngine *engine, uint index, Value v) const { d()->setProperty(e: engine, index, v); } |
167 | void setProperty(ExecutionEngine *engine, uint index, Heap::Base *b) const { d()->setProperty(e: engine, index, b); } |
168 | |
169 | const VTable *vtable() const { return d()->vtable(); } |
170 | |
171 | PropertyAttributes getOwnProperty(PropertyKey id, Property *p = nullptr) const { |
172 | return vtable()->getOwnProperty(this, id, p); |
173 | } |
174 | |
175 | PropertyIndex getValueOrSetter(PropertyKey id, PropertyAttributes *attrs); |
176 | |
177 | bool hasProperty(PropertyKey id) const { |
178 | return vtable()->hasProperty(this, id); |
179 | } |
180 | |
181 | bool defineOwnProperty(PropertyKey id, const Property *p, PropertyAttributes attrs) { |
182 | return vtable()->defineOwnProperty(this, id, p, attrs); |
183 | } |
184 | |
185 | // |
186 | // helpers |
187 | // |
188 | static ReturnedValue getValue(const Value *thisObject, const Value &v, PropertyAttributes attrs) { |
189 | if (attrs.isData()) |
190 | return v.asReturnedValue(); |
191 | return getValueAccessor(thisObject, v, attrs); |
192 | } |
193 | ReturnedValue getValue(const Value &v, PropertyAttributes attrs) const { |
194 | return getValue(thisObject: this, v, attrs); |
195 | } |
196 | ReturnedValue getValueByIndex(uint propertyIndex) const { |
197 | PropertyAttributes attrs = internalClass()->propertyData.at(i: propertyIndex); |
198 | const Value *v = propertyData(index: propertyIndex); |
199 | if (!attrs.isAccessor()) |
200 | return v->asReturnedValue(); |
201 | return getValueAccessor(thisObject: this, v: *v, attrs); |
202 | } |
203 | static ReturnedValue getValueAccessor(const Value *thisObject, const Value &v, PropertyAttributes attrs); |
204 | |
205 | bool putValue(uint memberIndex, PropertyAttributes attrs, const Value &value); |
206 | |
207 | /* The spec default: Writable: true, Enumerable: false, Configurable: true */ |
208 | void defineDefaultProperty(StringOrSymbol *name, const Value &value, PropertyAttributes attributes = Attr_Data|Attr_NotEnumerable) { |
209 | insertMember(s: name, v: value, attributes); |
210 | } |
211 | void defineDefaultProperty(const QString &name, const Value &value, PropertyAttributes attributes = Attr_Data|Attr_NotEnumerable); |
212 | void defineDefaultProperty(const QString &name, VTable::Call code, |
213 | int argumentCount = 0, PropertyAttributes attributes = Attr_Data|Attr_NotEnumerable); |
214 | void defineDefaultProperty(StringOrSymbol *name, VTable::Call code, |
215 | int argumentCount = 0, PropertyAttributes attributes = Attr_Data|Attr_NotEnumerable); |
216 | void defineAccessorProperty(const QString &name, VTable::Call getter, VTable::Call setter); |
217 | void defineAccessorProperty(StringOrSymbol *name, VTable::Call getter, VTable::Call setter); |
218 | /* Fixed: Writable: false, Enumerable: false, Configurable: false */ |
219 | void defineReadonlyProperty(const QString &name, const Value &value); |
220 | void defineReadonlyProperty(String *name, const Value &value); |
221 | |
222 | /* Fixed: Writable: false, Enumerable: false, Configurable: true */ |
223 | void defineReadonlyConfigurableProperty(const QString &name, const Value &value); |
224 | void defineReadonlyConfigurableProperty(StringOrSymbol *name, const Value &value); |
225 | |
226 | void addSymbolSpecies(); |
227 | |
228 | void insertMember(StringOrSymbol *s, const Value &v, PropertyAttributes attributes = Attr_Data) { |
229 | Scope scope(engine()); |
230 | ScopedProperty p(scope); |
231 | p->value = v; |
232 | insertMember(s, p, attributes); |
233 | } |
234 | void insertMember(StringOrSymbol *s, const Property *p, PropertyAttributes attributes); |
235 | |
236 | bool isExtensible() const { return vtable()->isExtensible(this); } |
237 | bool preventExtensions() { return vtable()->preventExtensions(this); } |
238 | Heap::Object *getPrototypeOf() const { return vtable()->getPrototypeOf(this); } |
239 | bool setPrototypeOf(const Object *p) { return vtable()->setPrototypeOf(this, p); } |
240 | void setPrototypeUnchecked(const Object *p); |
241 | |
242 | // Array handling |
243 | |
244 | public: |
245 | void copyArrayData(Object *other); |
246 | |
247 | bool setArrayLength(uint newLen); |
248 | void setArrayLengthUnchecked(uint l); |
249 | |
250 | void arraySet(uint index, const Property *p, PropertyAttributes attributes = Attr_Data); |
251 | void arraySet(uint index, const Value &value); |
252 | |
253 | bool arrayPut(uint index, const Value &value) { |
254 | return arrayData()->vtable()->put(this, index, value); |
255 | } |
256 | bool arrayPut(uint index, const Value *values, uint n) { |
257 | return arrayData()->vtable()->putArray(this, index, values, n); |
258 | } |
259 | void setArrayAttributes(uint i, PropertyAttributes a) { |
260 | Q_ASSERT(arrayData()); |
261 | if (d()->arrayData->attrs || a != Attr_Data) { |
262 | ArrayData::ensureAttributes(o: this); |
263 | a.resolve(); |
264 | arrayData()->vtable()->setAttribute(this, i, a); |
265 | } |
266 | } |
267 | |
268 | void push_back(const Value &v); |
269 | |
270 | ArrayData::Type arrayType() const { |
271 | return arrayData() ? static_cast<ArrayData::Type>(d()->arrayData->type) : Heap::ArrayData::Simple; |
272 | } |
273 | // ### remove me |
274 | void setArrayType(ArrayData::Type t) { |
275 | Q_ASSERT(t != Heap::ArrayData::Simple && t != Heap::ArrayData::Sparse); |
276 | arrayCreate(); |
277 | d()->arrayData->type = t; |
278 | } |
279 | |
280 | inline void arrayReserve(uint n) { |
281 | ArrayData::realloc(o: this, newType: Heap::ArrayData::Simple, alloc: n, enforceAttributes: false); |
282 | } |
283 | |
284 | void arrayCreate() { |
285 | if (!arrayData()) |
286 | ArrayData::realloc(o: this, newType: Heap::ArrayData::Simple, alloc: 0, enforceAttributes: false); |
287 | #ifdef CHECK_SPARSE_ARRAYS |
288 | initSparseArray(); |
289 | #endif |
290 | } |
291 | |
292 | void initSparseArray(); |
293 | SparseArrayNode *sparseBegin() const { return arrayType() == Heap::ArrayData::Sparse ? d()->arrayData->sparse->begin() : nullptr; } |
294 | SparseArrayNode *sparseEnd() const { return arrayType() == Heap::ArrayData::Sparse ? d()->arrayData->sparse->end() : nullptr; } |
295 | |
296 | inline bool protoHasArray() { |
297 | Scope scope(engine()); |
298 | ScopedObject p(scope, this); |
299 | |
300 | while ((p = p->getPrototypeOf())) |
301 | if (p->arrayData()) |
302 | return true; |
303 | |
304 | return false; |
305 | } |
306 | |
307 | inline ReturnedValue get(StringOrSymbol *name, bool *hasProperty = nullptr, const Value *receiver = nullptr) const |
308 | { if (!receiver) receiver = this; return vtable()->get(this, name->toPropertyKey(), receiver, hasProperty); } |
309 | inline ReturnedValue get(uint idx, bool *hasProperty = nullptr, const Value *receiver = nullptr) const |
310 | { if (!receiver) receiver = this; return vtable()->get(this, PropertyKey::fromArrayIndex(idx), receiver, hasProperty); } |
311 | QT_DEPRECATED inline ReturnedValue getIndexed(uint idx, bool *hasProperty = nullptr) const |
312 | { return get(idx, hasProperty); } |
313 | inline ReturnedValue get(PropertyKey id, const Value *receiver = nullptr, bool *hasProperty = nullptr) const |
314 | { if (!receiver) receiver = this; return vtable()->get(this, id, receiver, hasProperty); } |
315 | |
316 | // use the set variants instead, to customize throw behavior |
317 | inline bool put(StringOrSymbol *name, const Value &v, Value *receiver = nullptr) |
318 | { if (!receiver) receiver = this; return vtable()->put(this, name->toPropertyKey(), v, receiver); } |
319 | inline bool put(uint idx, const Value &v, Value *receiver = nullptr) |
320 | { if (!receiver) receiver = this; return vtable()->put(this, PropertyKey::fromArrayIndex(idx), v, receiver); } |
321 | QT_DEPRECATED inline bool putIndexed(uint idx, const Value &v) |
322 | { return put(idx, v); } |
323 | inline bool put(PropertyKey id, const Value &v, Value *receiver = nullptr) |
324 | { if (!receiver) receiver = this; return vtable()->put(this, id, v, receiver); } |
325 | |
326 | enum ThrowOnFailure { |
327 | DoThrowOnRejection, |
328 | DoNotThrow |
329 | }; |
330 | |
331 | // This is the same as set(), but it doesn't require creating a string key, |
332 | // which is much more efficient for the array case. |
333 | inline bool setIndexed(uint idx, const Value &v, ThrowOnFailure shouldThrow) |
334 | { |
335 | bool ret = vtable()->put(this, PropertyKey::fromArrayIndex(idx), v, this); |
336 | // ES6: 7.3.3, 6: If success is false and Throw is true, throw a TypeError exception. |
337 | if (!ret && shouldThrow == ThrowOnFailure::DoThrowOnRejection) { |
338 | ExecutionEngine *e = engine(); |
339 | if (!e->hasException) { // allow a custom set impl to throw itself |
340 | QString message = QLatin1String("Cannot assign to read-only property \"" ) + |
341 | QString::number(idx) + QLatin1Char('\"'); |
342 | e->throwTypeError(message); |
343 | } |
344 | } |
345 | return ret; |
346 | } |
347 | |
348 | // ES6: 7.3.3 Set (O, P, V, Throw) |
349 | inline bool set(StringOrSymbol *name, const Value &v, ThrowOnFailure shouldThrow) |
350 | { |
351 | bool ret = vtable()->put(this, name->toPropertyKey(), v, this); |
352 | // ES6: 7.3.3, 6: If success is false and Throw is true, throw a TypeError exception. |
353 | if (!ret && shouldThrow == ThrowOnFailure::DoThrowOnRejection) { |
354 | ExecutionEngine *e = engine(); |
355 | if (!e->hasException) { // allow a custom set impl to throw itself |
356 | QString message = QLatin1String("Cannot assign to read-only property \"" ) + |
357 | name->toQString() + QLatin1Char('\"'); |
358 | e->throwTypeError(message); |
359 | } |
360 | } |
361 | return ret; |
362 | } |
363 | |
364 | bool deleteProperty(PropertyKey id) |
365 | { return vtable()->deleteProperty(this, id); } |
366 | OwnPropertyKeyIterator *ownPropertyKeys(Value *target) const |
367 | { return vtable()->ownPropertyKeys(this, target); } |
368 | qint64 getLength() const { return vtable()->getLength(this); } |
369 | ReturnedValue instanceOf(const Value &var) const |
370 | { return vtable()->instanceOf(this, var); } |
371 | |
372 | bool isConcatSpreadable() const; |
373 | bool isArray() const; |
374 | const FunctionObject *speciesConstructor(Scope &scope, const FunctionObject *defaultConstructor) const; |
375 | |
376 | bool setProtoFromNewTarget(const Value *newTarget); |
377 | |
378 | ReturnedValue resolveLookupGetter(ExecutionEngine *engine, Lookup *lookup) const |
379 | { return vtable()->resolveLookupGetter(this, engine, lookup); } |
380 | ReturnedValue resolveLookupSetter(ExecutionEngine *engine, Lookup *lookup, const Value &value) |
381 | { return vtable()->resolveLookupSetter(this, engine, lookup, value); } |
382 | |
383 | protected: |
384 | static ReturnedValue virtualGet(const Managed *m, PropertyKey id, const Value *receiver,bool *hasProperty); |
385 | static bool virtualPut(Managed *m, PropertyKey id, const Value &value, Value *receiver); |
386 | static bool virtualDeleteProperty(Managed *m, PropertyKey id); |
387 | static bool virtualHasProperty(const Managed *m, PropertyKey id); |
388 | static PropertyAttributes virtualGetOwnProperty(const Managed *m, PropertyKey id, Property *p); |
389 | static bool virtualDefineOwnProperty(Managed *m, PropertyKey id, const Property *p, PropertyAttributes attrs); |
390 | static bool virtualIsExtensible(const Managed *m); |
391 | static bool virtualPreventExtensions(Managed *); |
392 | static Heap::Object *virtualGetPrototypeOf(const Managed *); |
393 | static bool virtualSetPrototypeOf(Managed *, const Object *); |
394 | static OwnPropertyKeyIterator *virtualOwnPropertyKeys(const Object *m, Value *target); |
395 | static qint64 virtualGetLength(const Managed *m); |
396 | static ReturnedValue virtualInstanceOf(const Object *typeObject, const Value &var); |
397 | static ReturnedValue virtualResolveLookupGetter(const Object *object, ExecutionEngine *engine, Lookup *lookup); |
398 | static bool virtualResolveLookupSetter(Object *object, ExecutionEngine *engine, Lookup *lookup, const Value &value); |
399 | public: |
400 | // qv4runtime uses this directly |
401 | static ReturnedValue checkedInstanceOf(ExecutionEngine *engine, const FunctionObject *typeObject, const Value &var); |
402 | |
403 | private: |
404 | bool internalDefineOwnProperty(ExecutionEngine *engine, uint index, const InternalClassEntry *memberEntry, const Property *p, PropertyAttributes attrs); |
405 | ReturnedValue internalGet(PropertyKey id, const Value *receiver, bool *hasProperty) const; |
406 | bool internalPut(PropertyKey id, const Value &value, Value *receiver); |
407 | bool internalDeleteProperty(PropertyKey id); |
408 | |
409 | friend struct ObjectIterator; |
410 | friend struct ObjectPrototype; |
411 | }; |
412 | |
413 | struct Q_QML_PRIVATE_EXPORT ObjectOwnPropertyKeyIterator : OwnPropertyKeyIterator |
414 | { |
415 | uint arrayIndex = 0; |
416 | uint memberIndex = 0; |
417 | bool iterateOverSymbols = false; |
418 | ~ObjectOwnPropertyKeyIterator() override = default; |
419 | PropertyKey next(const Object *o, Property *pd = nullptr, PropertyAttributes *attrs = nullptr) override; |
420 | |
421 | }; |
422 | |
423 | namespace Heap { |
424 | |
425 | struct BooleanObject : Object { |
426 | void init() { Object::init(); } |
427 | void init(bool b) { |
428 | Object::init(); |
429 | this->b = b; |
430 | } |
431 | |
432 | bool b; |
433 | }; |
434 | |
435 | struct NumberObject : Object { |
436 | void init() { Object::init(); } |
437 | void init(double val) { |
438 | Object::init(); |
439 | value = val; |
440 | } |
441 | |
442 | double value; |
443 | }; |
444 | |
445 | struct ArrayObject : Object { |
446 | enum { |
447 | LengthPropertyIndex = 0 |
448 | }; |
449 | |
450 | void init() { |
451 | Object::init(); |
452 | commonInit(); |
453 | } |
454 | |
455 | void init(const QStringList &list); |
456 | |
457 | private: |
458 | void commonInit() |
459 | { setProperty(e: internalClass->engine, index: LengthPropertyIndex, v: Value::fromInt32(i: 0)); } |
460 | }; |
461 | |
462 | } |
463 | |
464 | struct BooleanObject: Object { |
465 | V4_OBJECT2(BooleanObject, Object) |
466 | Q_MANAGED_TYPE(BooleanObject) |
467 | V4_PROTOTYPE(booleanPrototype) |
468 | |
469 | bool value() const { return d()->b; } |
470 | |
471 | }; |
472 | |
473 | struct NumberObject: Object { |
474 | V4_OBJECT2(NumberObject, Object) |
475 | Q_MANAGED_TYPE(NumberObject) |
476 | V4_PROTOTYPE(numberPrototype) |
477 | |
478 | double value() const { return d()->value; } |
479 | }; |
480 | |
481 | struct ArrayObject: Object { |
482 | V4_OBJECT2(ArrayObject, Object) |
483 | Q_MANAGED_TYPE(ArrayObject) |
484 | V4_INTERNALCLASS(ArrayObject) |
485 | V4_PROTOTYPE(arrayPrototype) |
486 | |
487 | void init(ExecutionEngine *engine); |
488 | |
489 | static qint64 virtualGetLength(const Managed *m); |
490 | |
491 | QStringList toQStringList() const; |
492 | protected: |
493 | static bool virtualDefineOwnProperty(Managed *m, PropertyKey id, const Property *p, PropertyAttributes attrs); |
494 | |
495 | }; |
496 | |
497 | inline void Object::setArrayLengthUnchecked(uint l) |
498 | { |
499 | if (isArrayObject()) |
500 | setProperty(index: Heap::ArrayObject::LengthPropertyIndex, v: Value::fromUInt32(i: l)); |
501 | } |
502 | |
503 | inline void Object::push_back(const Value &v) |
504 | { |
505 | arrayCreate(); |
506 | |
507 | uint idx = getLength(); |
508 | arrayReserve(n: idx + 1); |
509 | arrayPut(index: idx, value: v); |
510 | setArrayLengthUnchecked(idx + 1); |
511 | } |
512 | |
513 | inline void Object::arraySet(uint index, const Property *p, PropertyAttributes attributes) |
514 | { |
515 | // ### Clean up |
516 | arrayCreate(); |
517 | if (attributes.isAccessor() || (index > 0x1000 && index > 2*d()->arrayData->values.alloc)) { |
518 | initSparseArray(); |
519 | } else { |
520 | arrayData()->vtable()->reallocate(this, index + 1, false); |
521 | } |
522 | setArrayAttributes(i: index, a: attributes); |
523 | ArrayData::insert(o: this, index, v: &p->value, isAccessor: attributes.isAccessor()); |
524 | if (isArrayObject() && index >= getLength()) |
525 | setArrayLengthUnchecked(index + 1); |
526 | } |
527 | |
528 | |
529 | inline void Object::arraySet(uint index, const Value &value) |
530 | { |
531 | arrayCreate(); |
532 | if (index > 0x1000 && index > 2*d()->arrayData->values.alloc) { |
533 | initSparseArray(); |
534 | } |
535 | ArrayData::insert(o: this, index, v: &value); |
536 | if (isArrayObject() && index >= getLength()) |
537 | setArrayLengthUnchecked(index + 1); |
538 | } |
539 | |
540 | |
541 | template<> |
542 | inline const ArrayObject *Value::as() const { |
543 | return isManaged() && m()->internalClass->vtable->type == Managed::Type_ArrayObject ? static_cast<const ArrayObject *>(this) : nullptr; |
544 | } |
545 | |
546 | template<> |
547 | inline ReturnedValue value_convert<Object>(ExecutionEngine *e, const Value &v) |
548 | { |
549 | return v.toObject(e)->asReturnedValue(); |
550 | } |
551 | |
552 | } |
553 | |
554 | QT_END_NAMESPACE |
555 | |
556 | #endif // QMLJS_OBJECTS_H |
557 | |