Encapsulate and protect all accesses to the vtable of Heap objects
[platform/upstream/qtdeclarative.git] / src / qml / jsruntime / qv4persistent.cpp
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
34 #include "qv4persistent_p.h"
35 #include <private/qv4mm_p.h>
36 #include "qv4object_p.h"
37 #include "PageAllocation.h"
38
39 using namespace QV4;
40
41 namespace {
42
43 struct Page;
44 struct Header {
45     WTF::PageAllocation alloc;
46     ExecutionEngine *engine;
47     Page **prev;
48     Page *next;
49     int refCount;
50     int freeList;
51 };
52
53 static const int kEntriesPerPage = int((WTF::pageSize() - sizeof(Header)) / sizeof(Value));
54
55 struct Page {
56     Header header;
57     Value values[1]; // Really kEntriesPerPage, but keep the compiler happy
58 };
59
60 Page *getPage(Value *val) {
61    return reinterpret_cast<Page *>(reinterpret_cast<quintptr>(val) & ~((quintptr)(WTF::pageSize() - 1)));
62 }
63
64
65 Page *allocatePage(PersistentValueStorage *storage)
66 {
67     PageAllocation page = WTF::PageAllocation::allocate(WTF::pageSize());
68     Page *p = reinterpret_cast<Page *>(page.base());
69
70     Q_ASSERT(!((quintptr)p & (WTF::pageSize() - 1)));
71
72     p->header.engine = storage->engine;
73     p->header.alloc = page;
74     p->header.next = reinterpret_cast<Page *>(storage->firstPage);
75     p->header.prev = reinterpret_cast<Page **>(&storage->firstPage);
76     p->header.refCount = 0;
77     p->header.freeList = 0;
78     if (p->header.next)
79         p->header.next->header.prev = &p->header.next;
80     for (int i = 0; i < kEntriesPerPage - 1; ++i) {
81         p->values[i].setTag(QV4::Value::Empty_Type);
82         p->values[i].setInt_32(i + 1);
83     }
84     p->values[kEntriesPerPage - 1].setTag(QV4::Value::Empty_Type);
85     p->values[kEntriesPerPage - 1].setInt_32(-1);
86
87     storage->firstPage = p;
88
89     return p;
90 }
91
92
93 }
94
95
96 PersistentValueStorage::Iterator &PersistentValueStorage::Iterator::operator++() {
97     while (p) {
98         while (index < kEntriesPerPage - 1) {
99             ++index;
100             if (static_cast<Page *>(p)->values[index].tag() != QV4::Value::Empty_Type)
101                 return *this;
102         }
103         index = -1;
104         p = static_cast<Page *>(p)->header.next;
105     }
106     index = 0;
107     return *this;
108 }
109
110 Value &PersistentValueStorage::Iterator::operator *()
111 {
112     return static_cast<Page *>(p)->values[index];
113 }
114
115 PersistentValueStorage::PersistentValueStorage(ExecutionEngine *engine)
116     : engine(engine),
117       firstPage(0)
118 {
119 }
120
121 PersistentValueStorage::~PersistentValueStorage()
122 {
123     Page *p = static_cast<Page *>(firstPage);
124     while (p) {
125         for (int i = 0; i < kEntriesPerPage; ++i) {
126             if (!p->values[i].isEmpty())
127                 p->values[i] = Encode::undefined();
128         }
129         Page *n = p->header.next;
130         p->header.engine = 0;
131         p->header.prev = 0;
132         p->header.next = 0;
133         Q_ASSERT(p->header.refCount);
134         p = n;
135     }
136 }
137
138 Value *PersistentValueStorage::allocate()
139 {
140     Page *p = static_cast<Page *>(firstPage);
141     while (p) {
142         if (p->header.freeList != -1)
143             break;
144         p = p->header.next;
145     }
146     if (!p)
147         p = allocatePage(this);
148
149     Value *v = p->values + p->header.freeList;
150     p->header.freeList = v->int_32();
151     ++p->header.refCount;
152
153     v->setRawValue(Encode::undefined());
154
155     return v;
156 }
157
158 void PersistentValueStorage::free(Value *v)
159 {
160     if (!v)
161         return;
162
163     Page *p = getPage(v);
164
165     v->setTag(QV4::Value::Empty_Type);
166     v->setInt_32(p->header.freeList);
167     p->header.freeList = v - p->values;
168     if (!--p->header.refCount) {
169         if (p->header.prev)
170             *p->header.prev = p->header.next;
171         if (p->header.next)
172             p->header.next->header.prev = p->header.prev;
173         p->header.alloc.deallocate();
174     }
175 }
176
177 static void drainMarkStack(QV4::ExecutionEngine *engine, Value *markBase)
178 {
179     while (engine->jsStackTop > markBase) {
180         Heap::Base *h = engine->popForGC();
181         Q_ASSERT (h->vtable()->markObjects);
182         h->vtable()->markObjects(h, engine);
183     }
184 }
185
186 void PersistentValueStorage::mark(ExecutionEngine *e)
187 {
188     Value *markBase = e->jsStackTop;
189
190     Page *p = static_cast<Page *>(firstPage);
191     while (p) {
192         for (int i = 0; i < kEntriesPerPage; ++i) {
193             if (Managed *m = p->values[i].as<Managed>())
194                 m->mark(e);
195         }
196         drainMarkStack(e, markBase);
197
198         p = p->header.next;
199     }
200 }
201
202 ExecutionEngine *PersistentValueStorage::getEngine(Value *v)
203 {
204     return getPage(v)->header.engine;
205 }
206
207
208 PersistentValue::PersistentValue(const PersistentValue &other)
209     : val(0)
210 {
211     if (other.val) {
212         val = other.engine()->memoryManager->m_persistentValues->allocate();
213         *val = *other.val;
214     }
215 }
216
217 PersistentValue::PersistentValue(ExecutionEngine *engine, const Value &value)
218 {
219     val = engine->memoryManager->m_persistentValues->allocate();
220     *val = value;
221 }
222
223 PersistentValue::PersistentValue(ExecutionEngine *engine, ReturnedValue value)
224 {
225     val = engine->memoryManager->m_persistentValues->allocate();
226     *val = value;
227 }
228
229 PersistentValue::PersistentValue(ExecutionEngine *engine, Object *object)
230     : val(0)
231 {
232     if (!object)
233         return;
234
235     val = engine->memoryManager->m_persistentValues->allocate();
236     *val = object;
237 }
238
239 PersistentValue::~PersistentValue()
240 {
241     PersistentValueStorage::free(val);
242 }
243
244 PersistentValue &PersistentValue::operator=(const PersistentValue &other)
245 {
246     if (!val) {
247         if (!other.val)
248             return *this;
249         val = other.engine()->memoryManager->m_persistentValues->allocate();
250     }
251
252     Q_ASSERT(engine() == other.engine());
253
254     *val = *other.val;
255     return *this;
256 }
257
258 PersistentValue &PersistentValue::operator=(const WeakValue &other)
259 {
260     if (!val) {
261         if (!other.valueRef())
262             return *this;
263         val = other.engine()->memoryManager->m_persistentValues->allocate();
264     }
265
266     Q_ASSERT(engine() == other.engine());
267
268     *val = *other.valueRef();
269     return *this;
270 }
271
272 PersistentValue &PersistentValue::operator=(Object *object)
273 {
274     if (!object) {
275         PersistentValueStorage::free(val);
276         return *this;
277     }
278     if (!val)
279         val = object->engine()->memoryManager->m_persistentValues->allocate();
280
281     *val = object;
282     return *this;
283 }
284
285 void PersistentValue::set(ExecutionEngine *engine, const Value &value)
286 {
287     if (!val)
288         val = engine->memoryManager->m_persistentValues->allocate();
289     *val = value;
290 }
291
292 void PersistentValue::set(ExecutionEngine *engine, ReturnedValue value)
293 {
294     if (!val)
295         val = engine->memoryManager->m_persistentValues->allocate();
296     *val = value;
297 }
298
299 void PersistentValue::set(ExecutionEngine *engine, Heap::Base *obj)
300 {
301     if (!val)
302         val = engine->memoryManager->m_persistentValues->allocate();
303     *val = obj;
304 }
305
306 WeakValue::WeakValue(const WeakValue &other)
307     : val(0)
308 {
309     if (other.val) {
310         val = other.engine()->memoryManager->m_weakValues->allocate();
311         *val = *other.val;
312     }
313 }
314
315 WeakValue::WeakValue(ExecutionEngine *engine, const Value &value)
316 {
317     val = engine->memoryManager->m_weakValues->allocate();
318     *val = value;
319 }
320
321 WeakValue &WeakValue::operator=(const WeakValue &other)
322 {
323     if (!val) {
324         if (!other.val)
325             return *this;
326         val = other.engine()->memoryManager->m_weakValues->allocate();
327     }
328
329     Q_ASSERT(engine() == other.engine());
330
331     *val = *other.val;
332     return *this;
333 }
334
335 WeakValue::~WeakValue()
336 {
337     PersistentValueStorage::free(val);
338 }
339
340 void WeakValue::set(ExecutionEngine *engine, const Value &value)
341 {
342     if (!val)
343         val = engine->memoryManager->m_weakValues->allocate();
344     *val = value;
345 }
346
347 void WeakValue::set(ExecutionEngine *engine, ReturnedValue value)
348 {
349     if (!val)
350         val = engine->memoryManager->m_weakValues->allocate();
351     *val = value;
352 }
353
354 void WeakValue::set(ExecutionEngine *engine, Heap::Base *obj)
355 {
356     if (!val)
357         val = engine->memoryManager->m_weakValues->allocate();
358     *val = obj;
359 }
360
361 void WeakValue::markOnce(ExecutionEngine *e)
362 {
363     if (!val)
364         return;
365     val->mark(e);
366 }
367