Encapsulate and protect all accesses to the vtable of Heap objects
[platform/upstream/qtdeclarative.git] / src / qml / jsruntime / qv4object_p.h
1 /****************************************************************************
2 **
3 ** Copyright (C) 2015 The Qt Company Ltd.
4 ** Contact: http://www.qt.io/licensing/
5 **
6 ** This file is part of the QtQml module of the Qt Toolkit.
7 **
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.
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 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.
25 **
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.
29 **
30 ** $QT_END_LICENSE$
31 **
32 ****************************************************************************/
33 #ifndef QV4_OBJECT_H
34 #define QV4_OBJECT_H
35
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"
42
43 QT_BEGIN_NAMESPACE
44
45 namespace QV4 {
46
47 namespace Heap {
48
49 struct Object : Base {
50     inline Object(ExecutionEngine *engine);
51     Object(InternalClass *internal, QV4::Object *prototype);
52
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); }
55
56     InternalClass *internalClass;
57     Pointer<Object> prototype;
58     Pointer<MemberData> memberData;
59     Pointer<ArrayData> arrayData;
60 };
61
62 }
63
64 #define V4_OBJECT(superClass) \
65     public: \
66         Q_MANAGED_CHECK \
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()); }
72
73 #define V4_OBJECT2(DataClass, superClass) \
74     public: \
75         Q_MANAGED_CHECK \
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()); }
82
83 struct ObjectVTable
84 {
85     VTable vTable;
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);
100 };
101
102 #define DEFINE_OBJECT_VTABLE(classname) \
103 const QV4::ObjectVTable classname::static_vtbl =    \
104 {     \
105     DEFINE_MANAGED_VTABLE_INT(classname, &classname::SuperClass::static_vtbl == &Object::static_vtbl ? 0 : &classname::SuperClass::static_vtbl.vTable), \
106     call,                                       \
107     construct,                                  \
108     get,                                        \
109     getIndexed,                                 \
110     put,                                        \
111     putIndexed,                                 \
112     query,                                      \
113     queryIndexed,                               \
114     deleteProperty,                             \
115     deleteIndexedProperty,                      \
116     getLookup,                                  \
117     setLookup,                                  \
118     getLength,                                  \
119     advanceIterator                            \
120 }
121
122
123
124 struct Q_QML_EXPORT Object: Managed {
125     V4_OBJECT2(Object, Object)
126     Q_MANAGED_TYPE(Object)
127
128     enum {
129         IsObject = true
130     };
131
132     InternalClass *internalClass() const { return d()->internalClass; }
133     void setInternalClass(InternalClass *ic) { d()->internalClass = ic; }
134
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(); }
139
140     const Property *propertyAt(uint index) const { return d()->propertyAt(index); }
141     Property *propertyAt(uint index) { return d()->propertyAt(index); }
142
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);
146
147     void getOwnProperty(String *name, PropertyAttributes *attrs, Property *p = 0);
148     void getOwnProperty(uint index, PropertyAttributes *attrs, Property *p = 0);
149
150     Property *__getPropertyDescriptor__(String *name, PropertyAttributes *attrs) const;
151     Property *__getPropertyDescriptor__(uint index, PropertyAttributes *attrs) const;
152
153     bool hasProperty(String *name) const;
154     bool hasProperty(uint index) const;
155
156     bool hasOwnProperty(String *name) const;
157     bool hasOwnProperty(uint index) const;
158
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);
164
165     //
166     // helpers
167     //
168     void put(ExecutionEngine *engine, const QString &name, const Value &value);
169
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);
175     }
176
177     void putValue(Property *pd, PropertyAttributes attrs, const Value &value);
178
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);
182     }
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);
191
192     void ensureMemberIndex(QV4::ExecutionEngine *e, uint idx) {
193         d()->memberData = MemberData::reallocate(e, d()->memberData, idx);
194     }
195
196     void insertMember(String *s, const Value &v, PropertyAttributes attributes = Attr_Data) {
197         Scope scope(engine());
198         ScopedProperty p(scope);
199         p->value = v;
200         insertMember(s, p, attributes);
201     }
202     void insertMember(String *s, const Property *p, PropertyAttributes attributes);
203
204     inline ExecutionEngine *engine() const { return internalClass()->engine; }
205
206     bool isExtensible() const { return d()->internalClass->extensible; }
207
208     // Array handling
209
210 public:
211     void copyArrayData(Object *other);
212
213     bool setArrayLength(uint newLen);
214     void setArrayLengthUnchecked(uint l);
215
216     void arraySet(uint index, const Property *p, PropertyAttributes attributes = Attr_Data);
217     void arraySet(uint index, const Value &value);
218
219     bool arrayPut(uint index, const Value &value) {
220         return arrayData()->vtable()->put(this, index, value);
221     }
222     bool arrayPut(uint index, const Value *values, uint n) {
223         return arrayData()->vtable()->putArray(this, index, values, n);
224     }
225     void setArrayAttributes(uint i, PropertyAttributes a) {
226         Q_ASSERT(arrayData());
227         if (d()->arrayData->attrs || a != Attr_Data) {
228             ArrayData::ensureAttributes(this);
229             a.resolve();
230             arrayData()->vtable()->setAttribute(this, i, a);
231         }
232     }
233
234     void push_back(const Value &v);
235
236     ArrayData::Type arrayType() const {
237         return arrayData() ? d()->arrayData->type : Heap::ArrayData::Simple;
238     }
239     // ### remove me
240     void setArrayType(ArrayData::Type t) {
241         Q_ASSERT(t != Heap::ArrayData::Simple && t != Heap::ArrayData::Sparse);
242         arrayCreate();
243         d()->arrayData->type = t;
244     }
245
246     inline void arrayReserve(uint n) {
247         ArrayData::realloc(this, Heap::ArrayData::Simple, n, false);
248     }
249
250     void arrayCreate() {
251         if (!arrayData())
252             ArrayData::realloc(this, Heap::ArrayData::Simple, 0, false);
253 #ifdef CHECK_SPARSE_ARRAYS
254         initSparseArray();
255 #endif
256     }
257
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; }
261
262     inline bool protoHasArray() {
263         Scope scope(engine());
264         ScopedObject p(scope, this);
265
266         while ((p = p->prototype()))
267             if (p->arrayData())
268                 return true;
269
270         return false;
271     }
272     void ensureMemberIndex(uint idx);
273
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); }
297
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); }
302 protected:
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);
318
319 private:
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);
326
327     friend struct ObjectIterator;
328     friend struct ObjectPrototype;
329 };
330
331 namespace Heap {
332
333 inline Object::Object(ExecutionEngine *engine)
334     : internalClass(engine->emptyClass),
335       prototype(static_cast<Object *>(engine->objectPrototype()->m()))
336 {
337 }
338
339 struct BooleanObject : Object {
340     BooleanObject(InternalClass *ic, QV4::Object *prototype)
341         : Object(ic, prototype),
342           b(false)
343     {
344     }
345
346     BooleanObject(ExecutionEngine *engine, bool b)
347         : Object(engine->emptyClass, engine->booleanPrototype()),
348           b(b)
349     {
350     }
351     bool b;
352 };
353
354 struct NumberObject : Object {
355     NumberObject(InternalClass *ic, QV4::Object *prototype)
356         : Object(ic, prototype),
357           value(0)
358     {
359     }
360
361     NumberObject(ExecutionEngine *engine, double val)
362         : Object(engine->emptyClass, engine->numberPrototype()),
363           value(val)
364     {
365     }
366     double value;
367 };
368
369 struct ArrayObject : Object {
370     enum {
371         LengthPropertyIndex = 0
372     };
373
374     ArrayObject(ExecutionEngine *engine)
375         : Heap::Object(engine->arrayClass, engine->arrayPrototype())
376     { init(); }
377     ArrayObject(ExecutionEngine *engine, const QStringList &list);
378     ArrayObject(InternalClass *ic, QV4::Object *prototype)
379         : Heap::Object(ic, prototype)
380     { init(); }
381     void init()
382     { memberData->data[LengthPropertyIndex] = Primitive::fromInt32(0); }
383 };
384
385 }
386
387 struct BooleanObject: Object {
388     V4_OBJECT2(BooleanObject, Object)
389     Q_MANAGED_TYPE(BooleanObject)
390
391     bool value() const { return d()->b; }
392
393 };
394
395 struct NumberObject: Object {
396     V4_OBJECT2(NumberObject, Object)
397     Q_MANAGED_TYPE(NumberObject)
398
399     double value() const { return d()->value; }
400 };
401
402 struct ArrayObject: Object {
403     V4_OBJECT2(ArrayObject, Object)
404     Q_MANAGED_TYPE(ArrayObject)
405
406     void init(ExecutionEngine *engine);
407
408     static ReturnedValue getLookup(const Managed *m, Lookup *l);
409     using Object::getLength;
410     static uint getLength(const Managed *m);
411
412     QStringList toQStringList() const;
413 };
414
415 inline void Object::setArrayLengthUnchecked(uint l)
416 {
417     if (isArrayObject())
418         memberData()->data[Heap::ArrayObject::LengthPropertyIndex] = Primitive::fromUInt32(l);
419 }
420
421 inline void Object::push_back(const Value &v)
422 {
423     arrayCreate();
424
425     uint idx = getLength();
426     arrayReserve(idx + 1);
427     arrayPut(idx, v);
428     setArrayLengthUnchecked(idx + 1);
429 }
430
431 inline void Object::arraySet(uint index, const Property *p, PropertyAttributes attributes)
432 {
433     // ### Clean up
434     arrayCreate();
435     if (attributes.isAccessor() || (index > 0x1000 && index > 2*d()->arrayData->alloc)) {
436         initSparseArray();
437     } else {
438         arrayData()->vtable()->reallocate(this, index + 1, false);
439     }
440     setArrayAttributes(index, attributes);
441     Property *pd = ArrayData::insert(this, index, attributes.isAccessor());
442     pd->value = p->value;
443     if (attributes.isAccessor())
444         pd->set = p->set;
445     if (isArrayObject() && index >= getLength())
446         setArrayLengthUnchecked(index + 1);
447 }
448
449
450 inline void Object::arraySet(uint index, const Value &value)
451 {
452     arrayCreate();
453     if (index > 0x1000 && index > 2*d()->arrayData->alloc) {
454         initSparseArray();
455     }
456     Property *pd = ArrayData::insert(this, index);
457     pd->value = value;
458     if (isArrayObject() && index >= getLength())
459         setArrayLengthUnchecked(index + 1);
460 }
461
462
463 template<>
464 inline const ArrayObject *Value::as() const {
465     return isManaged() && m() && m()->vtable()->type == Managed::Type_ArrayObject ? static_cast<const ArrayObject *>(this) : 0;
466 }
467
468 #ifndef V4_BOOTSTRAP
469 template<>
470 inline ReturnedValue value_convert<Object>(ExecutionEngine *e, const Value &v)
471 {
472     return v.toObject(e)->asReturnedValue();
473 }
474 #endif
475
476 }
477
478 QT_END_NAMESPACE
479
480 #endif // QMLJS_OBJECTS_H