Qt
Internal/Contributor docs for the Qt SDK. Note: These are NOT official API docs; those are found at https://doc.qt.io/
Loading...
Searching...
No Matches
qv4object_p.h
Go to the documentation of this file.
1// Copyright (C) 2016 The Qt Company Ltd.
2// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
3// Qt-Security score:significant
4#ifndef QV4_OBJECT_H
5#define QV4_OBJECT_H
6
7//
8// W A R N I N G
9// -------------
10//
11// This file is not part of the Qt API. It exists purely as an
12// implementation detail. This header file may change from version to
13// version without notice, or even be removed.
14//
15// We mean it.
16//
17
18#include "qv4managed_p.h"
20#include "qv4arraydata_p.h"
21#include "qv4engine_p.h"
23#include "qv4value_p.h"
25
27
28
29namespace QV4 {
30
31namespace Heap {
32
33#define ObjectMembers(class, Member)
34 Member(class, Pointer, MemberData *, memberData)
35 Member(class, Pointer, ArrayData *, arrayData)
36
38 static void markObjects(Heap::Base *base, MarkStack *stack);
39 void init() { Base::init(); }
40
41 const VTable *vtable() const {
42 return internalClass->vtable;
43 }
44
45 const Value *inlinePropertyDataWithOffset(uint indexWithOffset) const {
46 Q_ASSERT(indexWithOffset >= vtable()->inlinePropertyOffset && indexWithOffset < uint(vtable()->inlinePropertyOffset + vtable()->nInlineProperties));
47 return reinterpret_cast<const Value *>(this) + indexWithOffset;
48 }
49 const Value *inlinePropertyData(uint index) const {
50 Q_ASSERT(index < vtable()->nInlineProperties);
51 return reinterpret_cast<const Value *>(this) + vtable()->inlinePropertyOffset + index;
52 }
53 void setInlinePropertyWithOffset(ExecutionEngine *e, uint indexWithOffset, Value v) {
54 Q_ASSERT(indexWithOffset >= vtable()->inlinePropertyOffset && indexWithOffset < uint(vtable()->inlinePropertyOffset + vtable()->nInlineProperties));
55 Value *prop = reinterpret_cast<Value *>(this) + indexWithOffset;
56 WriteBarrier::write(e, this, prop->data_ptr(), v.asReturnedValue());
57 }
58 void setInlinePropertyWithOffset(ExecutionEngine *e, uint indexWithOffset, Heap::Base *b) {
59 Q_ASSERT(indexWithOffset >= vtable()->inlinePropertyOffset && indexWithOffset < uint(vtable()->inlinePropertyOffset + vtable()->nInlineProperties));
60 Value *prop = reinterpret_cast<Value *>(this) + indexWithOffset;
61 WriteBarrier::write(e, this, prop->data_ptr(), Value::fromHeapObject(b).asReturnedValue());
62 }
63
64 PropertyIndex writablePropertyData(uint index) {
65 uint nInline = vtable()->nInlineProperties;
66 if (index < nInline)
67 return PropertyIndex{ this, reinterpret_cast<Value *>(this) + vtable()->inlinePropertyOffset + index};
68 index -= nInline;
69 return PropertyIndex{ memberData, memberData->values.values + index };
70 }
71
72 const Value *propertyData(uint index) const {
73 uint nInline = vtable()->nInlineProperties;
74 if (index < nInline)
75 return reinterpret_cast<const Value *>(this) + vtable()->inlinePropertyOffset + index;
76 index -= nInline;
77 return memberData->values.data() + index;
78 }
79 void setProperty(ExecutionEngine *e, uint index, Value v) {
80 uint nInline = vtable()->nInlineProperties;
81 if (index < nInline) {
82 setInlinePropertyWithOffset(e, index + vtable()->inlinePropertyOffset, v);
83 return;
84 }
85 index -= nInline;
86 memberData->values.set(e, index, v);
87 }
88 void setProperty(ExecutionEngine *e, uint index, Heap::Base *b) {
89 uint nInline = vtable()->nInlineProperties;
90 if (index < nInline) {
91 setInlinePropertyWithOffset(e, index + vtable()->inlinePropertyOffset, b);
92 return;
93 }
94 index -= nInline;
95 memberData->values.set(e, index, b);
96 }
97
98 void setUsedAsProto();
99
100 Heap::Object *prototype() const { return internalClass->prototype; }
101};
102
103}
104
110
111 enum { NInlineProperties = 2 };
112
113 enum {
114 IsObject = true,
117 };
118
120
121 const Value *propertyData(uint index) const { return d()->propertyData(index); }
122
123 Heap::ArrayData *arrayData() const { return d()->arrayData; }
124 void setArrayData(ArrayData *a) { d()->arrayData.set(engine(), a ? a->d() : nullptr); }
125
126 void getProperty(const InternalClassEntry &entry, Property *p) const;
127 void setProperty(const InternalClassEntry &entry, const Property *p);
128 void setProperty(uint index, Value v) const { d()->setProperty(engine(), index, v); }
129 void setProperty(uint index, Heap::Base *b) const { d()->setProperty(engine(), index, b); }
132
133 const VTable *vtable() const { return d()->vtable(); }
134
136 return vtable()->getOwnProperty(this, id, p);
137 }
138
140
142 return vtable()->hasProperty(this, id);
143 }
144
148
149 //
150 // helpers
151 //
153 if (attrs.isData())
154 return v.asReturnedValue();
156 }
158 return getValue(this, v, attrs);
159 }
168
170
171 /* The spec default: Writable: true, Enumerable: false, Configurable: true */
182 /* Fixed: Writable: false, Enumerable: false, Configurable: false */
183 void defineReadonlyProperty(const QString &name, const Value &value);
185
186 /* Fixed: Writable: false, Enumerable: false, Configurable: true */
189
190 void addSymbolSpecies();
191
199
200 bool isExtensible() const { return vtable()->isExtensible(this); }
201 bool preventExtensions() { return vtable()->preventExtensions(this); }
202 Heap::Object *getPrototypeOf() const { return vtable()->getPrototypeOf(this); }
203 bool setPrototypeOf(const Object *p) { return vtable()->setPrototypeOf(this, p); }
204 void setPrototypeUnchecked(const Object *p);
205
206 // Array handling
207
208public:
210
213
215 void arraySet(uint index, const Value &value);
216
217 bool arrayPut(uint index, const Value &value) {
218 return arrayData()->vtable()->put(this, index, value);
219 }
221 return arrayData()->vtable()->putArray(this, index, values, n);
222 }
225 if (d()->arrayData->attrs || a != Attr_Data) {
227 a.resolve();
228 arrayData()->vtable()->setAttribute(this, i, a);
229 }
230 }
231
232 void push_back(const Value &v);
233
235 return arrayData() ? static_cast<ArrayData::Type>(d()->arrayData->type) : Heap::ArrayData::Simple;
236 }
237 // ### remove me
240 arrayCreate();
241 d()->arrayData->type = t;
242 }
243
244 inline void arrayReserve(uint n) {
245 ArrayData::realloc(this, Heap::ArrayData::Simple, n, false);
246 }
247
248 void arrayCreate() {
249 if (!arrayData())
250 ArrayData::realloc(this, Heap::ArrayData::Simple, 0, false);
251#ifdef CHECK_SPARSE_ARRAYS
253#endif
254 }
255
256 void initSparseArray();
257 SparseArrayNode *sparseBegin() const { return arrayType() == Heap::ArrayData::Sparse ? d()->arrayData->sparse->begin() : nullptr; }
258 SparseArrayNode *sparseEnd() const { return arrayType() == Heap::ArrayData::Sparse ? d()->arrayData->sparse->end() : nullptr; }
259
260 inline bool protoHasArray() {
261 Scope scope(engine());
262 ScopedObject p(scope, this);
263
264 while ((p = p->getPrototypeOf()))
265 if (p->arrayData())
266 return true;
267
268 return false;
269 }
270
271 inline ReturnedValue get(StringOrSymbol *name, bool *hasProperty = nullptr, const Value *receiver = nullptr) const
272 { if (!receiver) receiver = this; return vtable()->get(this, name->toPropertyKey(), receiver, hasProperty); }
273 inline ReturnedValue get(uint idx, bool *hasProperty = nullptr, const Value *receiver = nullptr) const
274 { if (!receiver) receiver = this; return vtable()->get(this, PropertyKey::fromArrayIndex(idx), receiver, hasProperty); }
276 { return get(idx, hasProperty); }
277 inline ReturnedValue get(PropertyKey id, const Value *receiver = nullptr, bool *hasProperty = nullptr) const
278 { if (!receiver) receiver = this; return vtable()->get(this, id, receiver, hasProperty); }
279
280 // use the set variants instead, to customize throw behavior
281 inline bool put(StringOrSymbol *name, const Value &v, Value *receiver = nullptr)
282 { if (!receiver) receiver = this; return vtable()->put(this, name->toPropertyKey(), v, receiver); }
283 inline bool put(uint idx, const Value &v, Value *receiver = nullptr)
284 { if (!receiver) receiver = this; return vtable()->put(this, PropertyKey::fromArrayIndex(idx), v, receiver); }
285 QT_DEPRECATED inline bool putIndexed(uint idx, const Value &v)
286 { return put(idx, v); }
287 inline bool put(PropertyKey id, const Value &v, Value *receiver = nullptr)
288 { if (!receiver) receiver = this; return vtable()->put(this, id, v, receiver); }
289
294
295 // This is the same as set(), but it doesn't require creating a string key,
296 // which is much more efficient for the array case.
298 {
299 bool ret = vtable()->put(this, PropertyKey::fromArrayIndex(idx), v, this);
300 // ES6: 7.3.3, 6: If success is false and Throw is true, throw a TypeError exception.
303 if (!e->hasException) { // allow a custom set impl to throw itself
304 QString message = QLatin1String("Cannot assign to read-only property \"") +
305 QString::number(idx) + QLatin1Char('\"');
307 }
308 }
309 return ret;
310 }
311
312 // ES6: 7.3.3 Set (O, P, V, Throw)
314 {
315 bool ret = vtable()->put(this, name->toPropertyKey(), v, this);
316 // ES6: 7.3.3, 6: If success is false and Throw is true, throw a TypeError exception.
319 if (!e->hasException) { // allow a custom set impl to throw itself
320 QString message = QLatin1String("Cannot assign to read-only property \"") +
321 name->toQString() + QLatin1Char('\"');
323 }
324 }
325 return ret;
326 }
327
329 { return vtable()->deleteProperty(this, id); }
332 qint64 getLength() const { return vtable()->getLength(this); }
334 { return vtable()->instanceOf(this, var); }
335
336 bool isConcatSpreadable() const;
337 bool isArray() const;
339
341
346
347 int metacall(QMetaObject::Call call, int index, void **a)
348 { return vtable()->metacall(this, call, index, a); }
349
350protected:
352 static bool virtualPut(Managed *m, PropertyKey id, const Value &value, Value *receiver);
354 static bool virtualHasProperty(const Managed *m, PropertyKey id);
357 static bool virtualIsExtensible(const Managed *m);
358 static bool virtualPreventExtensions(Managed *);
359 static Heap::Object *virtualGetPrototypeOf(const Managed *);
360 static bool virtualSetPrototypeOf(Managed *, const Object *);
362 static qint64 virtualGetLength(const Managed *m);
366 static int virtualMetacall(Object *object, QMetaObject::Call call, int index, void **a);
367public:
368 // qv4runtime uses this directly
370
371private:
376
377 friend struct ObjectIterator;
378 friend struct ObjectPrototype;
379};
380
382{
384 uint memberIndex = 0;
385 bool iterateOverSymbols = false;
387 PropertyKey next(const Object *o, Property *pd = nullptr, PropertyAttributes *attrs = nullptr) override;
388
389};
390
391namespace Heap {
392
394 void init() { Object::init(); }
395 void init(bool b) {
396 Object::init();
397 this->b = b;
398 }
399
400 bool b;
401};
402
404 void init() { Object::init(); }
405 void init(double val) {
406 Object::init();
407 value = val;
408 }
409
410 double value;
411};
412
414 enum {
416 };
417
418 void init() {
419 Object::init();
420 commonInit();
421 }
422
423 void init(const QStringList &list);
424
425private:
426 void commonInit()
427 { setProperty(internalClass->engine, LengthPropertyIndex, Value::fromInt32(0)); }
428};
429
430}
431
433 V4_OBJECT2(BooleanObject, Object)
435 V4_PROTOTYPE(booleanPrototype)
436
437 bool value() const { return d()->b; }
438
439};
440
442 V4_OBJECT2(NumberObject, Object)
444 V4_PROTOTYPE(numberPrototype)
445
446 double value() const { return d()->value; }
447};
448
450 V4_OBJECT2(ArrayObject, Object)
452 V4_INTERNALCLASS(ArrayObject)
453 V4_PROTOTYPE(arrayPrototype)
454
456
457 static qint64 virtualGetLength(const Managed *m);
458
460protected:
461 static bool virtualDefineOwnProperty(Managed *m, PropertyKey id, const Property *p, PropertyAttributes attrs);
462
463};
464
465inline void Object::setArrayLengthUnchecked(uint l)
466{
467 if (isArrayObject())
468 setProperty(Heap::ArrayObject::LengthPropertyIndex, Value::fromUInt32(l));
469}
470
471inline void Object::push_back(const Value &v)
472{
473 arrayCreate();
474
475 const auto length = getLength();
476 if (Q_UNLIKELY(length == std::numeric_limits<uint>::max())) {
477 engine()->throwRangeError(QLatin1String("Too many elements."));
478 return;
479 }
480 uint idx = uint(length);
481 arrayReserve(idx + 1);
482 arrayPut(idx, v);
483 setArrayLengthUnchecked(idx + 1);
484}
485
486inline void Object::arraySet(uint index, const Property *p, PropertyAttributes attributes)
487{
488 // ### Clean up
489 arrayCreate();
490 if (attributes.isAccessor() || (index > 0x1000 && index > 2*d()->arrayData->values.alloc)) {
491 initSparseArray();
492 } else {
493 arrayData()->vtable()->reallocate(this, index + 1, false);
494 }
495 setArrayAttributes(index, attributes);
496 ArrayData::insert(this, index, &p->value, attributes.isAccessor());
497 if (isArrayObject() && index >= getLength())
498 setArrayLengthUnchecked(index + 1);
499}
500
501
502inline void Object::arraySet(uint index, const Value &value)
503{
504 arrayCreate();
505 if (index > 0x1000 && index > 2*d()->arrayData->values.alloc) {
506 initSparseArray();
507 }
508 ArrayData::insert(this, index, &value);
509 if (isArrayObject() && index >= getLength())
510 setArrayLengthUnchecked(index + 1);
511}
512
513
514template<>
515inline const ArrayObject *Value::as() const {
516 return isManaged() && m()->internalClass->vtable->type == Managed::Type_ArrayObject ? static_cast<const ArrayObject *>(this) : nullptr;
517}
518
519template<>
520inline ReturnedValue value_convert<Object>(ExecutionEngine *e, const Value &v)
521{
522 return v.toObject(e)->asReturnedValue();
523}
524
525}
526
527QT_END_NAMESPACE
528
529#endif // QMLJS_OBJECTS_H
DECLARE_HEAP_OBJECT(StrictArgumentsObject, Object)
DECLARE_EXPORTED_HEAP_OBJECT(Object, Base)
Definition qv4object_p.h:37
DECLARE_HEAP_OBJECT(ArgumentsObject, Object)
Definition qjsvalue.h:23
DEFINE_OBJECT_VTABLE(StrictArgumentsObject)
DEFINE_OBJECT_VTABLE(ArgumentsObject)
#define Q_MANAGED_TYPE(type)
#define V4_INTERNALCLASS(c)
static qint64 virtualGetLength(const Managed *m)
static bool virtualDefineOwnProperty(Managed *m, PropertyKey id, const Property *desc, PropertyAttributes attrs)
Heap::CallContext * context() const
static ReturnedValue virtualGet(const Managed *m, PropertyKey id, const Value *receiver, bool *hasProperty)
static OwnPropertyKeyIterator * virtualOwnPropertyKeys(const Object *m, Value *target)
static bool isNonStrictArgumentsObject(Managed *m)
static bool virtualDeleteProperty(Managed *m, PropertyKey id)
static PropertyAttributes virtualGetOwnProperty(const Managed *m, PropertyKey id, Property *p)
bool isMapped(uint arg) const
static bool virtualPut(Managed *m, PropertyKey id, const Value &value, Value *receiver)
static bool virtualDefineOwnProperty(Managed *m, PropertyKey id, const Property *p, PropertyAttributes attrs)
static qint64 virtualGetLength(const Managed *m)
QStringList toQStringList() const
void init(const QStringList &list)
void init(double val)
PropertyKey next(const Object *o, Property *pd=nullptr, PropertyAttributes *attrs=nullptr) override