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 QV4ARRAYDATA_H
40 #define QV4ARRAYDATA_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 "qv4global_p.h"
54 #include "qv4managed_p.h"
55 #include "qv4property_p.h"
56 #include "qv4sparsearray_p.h"
57 
58 QT_BEGIN_NAMESPACE
59 
60 namespace QV4 {
61 
62 #define V4_ARRAYDATA(DataClass) \
63     public: \
64         Q_MANAGED_CHECK \
65         typedef QV4::Heap::DataClass Data; \
66         static const QV4::ArrayVTable static_vtbl; \
67         static inline const QV4::VTable *staticVTable() { return &static_vtbl.vTable; } \
68         V4_MANAGED_SIZE_TEST \
69         const Data *d() const { return static_cast<const Data *>(m()); } \
70         Data *d() { return static_cast<Data *>(m()); }
71 
72 
73 struct ArrayData;
74 
75 struct ArrayVTable
76 {
77     VTable vTable;
78     uint type;
79     Heap::ArrayData *(*reallocate)(Object *o, uint n, bool enforceAttributes);
80     ReturnedValue (*get)(const Heap::ArrayData *d, uint index);
81     bool (*put)(Object *o, uint index, const Value &value);
82     bool (*putArray)(Object *o, uint index, const Value *values, uint n);
83     bool (*del)(Object *o, uint index);
84     void (*setAttribute)(Object *o, uint index, PropertyAttributes attrs);
85     void (*push_front)(Object *o, const Value *values, uint n);
86     ReturnedValue (*pop_front)(Object *o);
87     uint (*truncate)(Object *o, uint newLen);
88     uint (*length)(const Heap::ArrayData *d);
89 };
90 
91 namespace Heap {
92 
93 #define ArrayDataMembers(class, Member) \
94     Member(class, NoMark, ushort, type) \
95     Member(class, NoMark, ushort, unused) \
96     Member(class, NoMark, uint, offset) \
97     Member(class, NoMark, PropertyAttributes *, attrs) \
98     Member(class, NoMark, SparseArray *, sparse) \
99     Member(class, ValueArray, ValueArray, values)
100 
DECLARE_HEAP_OBJECT(ArrayData,Base)101 DECLARE_HEAP_OBJECT(ArrayData, Base) {
102     static void markObjects(Heap::Base *base, MarkStack *stack);
103 
104     enum Type { Simple = 0, Sparse = 1, Custom = 2 };
105 
106     bool isSparse() const { return type == Sparse; }
107 
108     const ArrayVTable *vtable() const { return reinterpret_cast<const ArrayVTable *>(internalClass->vtable); }
109 
110     inline ReturnedValue get(uint i) const {
111         return vtable()->get(this, i);
112     }
113     inline bool getProperty(uint index, Property *p, PropertyAttributes *attrs);
114     inline void setProperty(EngineBase *e, uint index, const Property *p);
115     inline PropertyIndex getValueOrSetter(uint index, PropertyAttributes *attrs);
116     inline PropertyAttributes attributes(uint i) const;
117 
118     bool isEmpty(uint i) const {
119         return get(i) == Value::emptyValue().asReturnedValue();
120     }
121 
122     inline uint length() const {
123         return vtable()->length(this);
124     }
125 
126     void setArrayData(EngineBase *e, uint index, Value newVal) {
127         values.set(e, index, newVal);
128     }
129 
130     uint mappedIndex(uint index) const;
131 };
132 Q_STATIC_ASSERT(std::is_trivial< ArrayData >::value);
133 
134 struct SimpleArrayData : public ArrayData {
mappedIndexSimpleArrayData135     uint mappedIndex(uint index) const { index += offset; if (index >= values.alloc) index -= values.alloc; return index; }
dataSimpleArrayData136     const Value &data(uint index) const { return values[mappedIndex(index)]; }
setDataSimpleArrayData137     void setData(EngineBase *e, uint index, Value newVal) {
138         values.set(e, mappedIndex(index), newVal);
139     }
140 
attributesSimpleArrayData141     PropertyAttributes attributes(uint i) const {
142         return attrs ? attrs[i] : Attr_Data;
143     }
144 };
145 Q_STATIC_ASSERT(std::is_trivial< SimpleArrayData >::value);
146 
147 struct SparseArrayData : public ArrayData {
destroySparseArrayData148     void destroy() {
149         delete sparse;
150         ArrayData::destroy();
151     }
152 
mappedIndexSparseArrayData153     uint mappedIndex(uint index) const {
154         SparseArrayNode *n = sparse->findNode(index);
155         if (!n)
156             return UINT_MAX;
157         return n->value;
158     }
159 
attributesSparseArrayData160     PropertyAttributes attributes(uint i) const {
161         if (!attrs)
162             return Attr_Data;
163         uint index = mappedIndex(i);
164         return index < UINT_MAX ? attrs[index] : Attr_Data;
165     }
166 };
167 
168 }
169 
170 struct Q_QML_EXPORT ArrayData : public Managed
171 {
172     typedef Heap::ArrayData::Type Type;
173     V4_MANAGED(ArrayData, Managed)
174     enum {
175         IsArrayData = true
176     };
177 
allocArrayData178     uint alloc() const { return d()->values.alloc; }
allocArrayData179     uint &alloc() { return d()->values.alloc; }
setAllocArrayData180     void setAlloc(uint a) { d()->values.alloc = a; }
typeArrayData181     Type type() const { return static_cast<Type>(d()->type); }
setTypeArrayData182     void setType(Type t) { d()->type = t; }
attrsArrayData183     PropertyAttributes *attrs() const { return d()->attrs; }
setAttrsArrayData184     void setAttrs(PropertyAttributes *a) { d()->attrs = a; }
arrayDataArrayData185     const Value *arrayData() const { return d()->values.data(); }
setArrayDataArrayData186     void setArrayData(EngineBase *e, uint index, Value newVal) {
187         d()->setArrayData(e, index, newVal);
188     }
189 
vtableArrayData190     const ArrayVTable *vtable() const { return d()->vtable(); }
isSparseArrayData191     bool isSparse() const { return type() == Heap::ArrayData::Sparse; }
192 
lengthArrayData193     uint length() const {
194         return d()->length();
195     }
196 
hasAttributesArrayData197     bool hasAttributes() const {
198         return attrs();
199     }
attributesArrayData200     PropertyAttributes attributes(uint i) const {
201         return d()->attributes(i);
202     }
203 
isEmptyArrayData204     bool isEmpty(uint i) const {
205         return d()->isEmpty(i);
206     }
207 
getArrayData208     ReturnedValue get(uint i) const {
209         return d()->get(i);
210     }
211 
212     static void ensureAttributes(Object *o);
213     static void realloc(Object *o, Type newType, uint alloc, bool enforceAttributes);
214 
215     static void sort(ExecutionEngine *engine, Object *thisObject, const Value &comparefn, uint dataLen);
216     static uint append(Object *obj, ArrayObject *otherObj, uint n);
217     static void insert(Object *o, uint index, const Value *v, bool isAccessor = false);
218 };
219 
220 struct Q_QML_EXPORT SimpleArrayData : public ArrayData
221 {
222     V4_ARRAYDATA(SimpleArrayData)
V4_INTERNALCLASSSimpleArrayData223     V4_INTERNALCLASS(SimpleArrayData)
224 
225     uint mappedIndex(uint index) const { return d()->mappedIndex(index); }
dataSimpleArrayData226     Value data(uint index) const { return d()->data(index); }
227 
lenSimpleArrayData228     uint &len() { return d()->values.size; }
lenSimpleArrayData229     uint len() const { return d()->values.size; }
230 
231     static Heap::ArrayData *reallocate(Object *o, uint n, bool enforceAttributes);
232 
233     static ReturnedValue get(const Heap::ArrayData *d, uint index);
234     static bool put(Object *o, uint index, const Value &value);
235     static bool putArray(Object *o, uint index, const Value *values, uint n);
236     static bool del(Object *o, uint index);
237     static void setAttribute(Object *o, uint index, PropertyAttributes attrs);
238     static void push_front(Object *o, const Value *values, uint n);
239     static ReturnedValue pop_front(Object *o);
240     static uint truncate(Object *o, uint newLen);
241     static uint length(const Heap::ArrayData *d);
242 };
243 
244 struct Q_QML_EXPORT SparseArrayData : public ArrayData
245 {
246     V4_ARRAYDATA(SparseArrayData)
V4_INTERNALCLASSSparseArrayData247     V4_INTERNALCLASS(SparseArrayData)
248     V4_NEEDS_DESTROY
249 
250     SparseArray *sparse() const { return d()->sparse; }
setSparseSparseArrayData251     void setSparse(SparseArray *s) { d()->sparse = s; }
252 
253     static uint allocate(Object *o, bool doubleSlot = false);
254     static void free(Heap::ArrayData *d, uint idx);
255 
mappedIndexSparseArrayData256     uint mappedIndex(uint index) const { return d()->mappedIndex(index); }
257 
258     static Heap::ArrayData *reallocate(Object *o, uint n, bool enforceAttributes);
259     static ReturnedValue get(const Heap::ArrayData *d, uint index);
260     static bool put(Object *o, uint index, const Value &value);
261     static bool putArray(Object *o, uint index, const Value *values, uint n);
262     static bool del(Object *o, uint index);
263     static void setAttribute(Object *o, uint index, PropertyAttributes attrs);
264     static void push_front(Object *o, const Value *values, uint n);
265     static ReturnedValue pop_front(Object *o);
266     static uint truncate(Object *o, uint newLen);
267     static uint length(const Heap::ArrayData *d);
268 };
269 
270 namespace Heap {
271 
mappedIndex(uint index)272 inline uint ArrayData::mappedIndex(uint index) const
273 {
274     if (isSparse())
275         return static_cast<const SparseArrayData *>(this)->mappedIndex(index);
276     if (index >= values.size)
277         return UINT_MAX;
278     uint idx = static_cast<const SimpleArrayData *>(this)->mappedIndex(index);
279     return values[idx].isEmpty() ? UINT_MAX : idx;
280 }
281 
getProperty(uint index,Property * p,PropertyAttributes * attrs)282 bool ArrayData::getProperty(uint index, Property *p, PropertyAttributes *attrs)
283 {
284     uint mapped = mappedIndex(index);
285     if (mapped == UINT_MAX) {
286         *attrs = Attr_Invalid;
287         return false;
288     }
289 
290     *attrs = attributes(index);
291     if (p) {
292         p->value = *(PropertyIndex{ this, values.values + mapped });
293         if (attrs->isAccessor())
294             p->set = *(PropertyIndex{ this, values.values + mapped + 1 /*Object::SetterOffset*/ });
295     }
296     return true;
297 }
298 
setProperty(QV4::EngineBase * e,uint index,const Property * p)299 void ArrayData::setProperty(QV4::EngineBase *e, uint index, const Property *p)
300 {
301     uint mapped = mappedIndex(index);
302     Q_ASSERT(mapped != UINT_MAX);
303     values.set(e, mapped, p->value);
304     if (attributes(index).isAccessor())
305         values.set(e, mapped + 1 /*QV4::Object::SetterOffset*/, p->set);
306 }
307 
attributes(uint i)308 inline PropertyAttributes ArrayData::attributes(uint i) const
309 {
310     if (isSparse())
311         return static_cast<const SparseArrayData *>(this)->attributes(i);
312     return static_cast<const SimpleArrayData *>(this)->attributes(i);
313 }
314 
getValueOrSetter(uint index,PropertyAttributes * attrs)315 PropertyIndex ArrayData::getValueOrSetter(uint index, PropertyAttributes *attrs)
316 {
317     uint idx = mappedIndex(index);
318     if (idx == UINT_MAX) {
319         *attrs = Attr_Invalid;
320         return { nullptr, nullptr };
321     }
322 
323     *attrs = attributes(index);
324     if (attrs->isAccessor())
325         ++idx;
326     return { this, values.values + idx };
327 }
328 
329 
330 
331 }
332 
333 }
334 
335 QT_END_NAMESPACE
336 
337 #endif
338