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 QV4SCOPEDVALUE_P_H
40#define QV4SCOPEDVALUE_P_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 "qv4engine_p.h"
54#include "qv4value_p.h"
55#include "qv4property_p.h"
56#include "qv4propertykey_p.h"
57
58#ifdef V4_USE_VALGRIND
59#include <valgrind/memcheck.h>
60#endif
61
62QT_BEGIN_NAMESPACE
63
64#define SAVE_JS_STACK(ctx) Value *__jsStack = ctx->engine->jsStackTop
65#define CHECK_JS_STACK(ctx) Q_ASSERT(__jsStack == ctx->engine->jsStackTop)
66
67namespace QV4 {
68
69struct ScopedValue;
70
71#define CHECK_EXCEPTION() \
72 do { \
73 if (scope.hasException() || scope.engine->isInterrupted.loadAcquire()) { \
74 return QV4::Encode::undefined(); \
75 } \
76 } while (false)
77
78#define RETURN_UNDEFINED() \
79 return QV4::Encode::undefined()
80
81#define RETURN_RESULT(r) \
82 return QV4::Encode(r)
83
84#define THROW_TYPE_ERROR() \
85 return scope.engine->throwTypeError()
86
87#define THROW_GENERIC_ERROR(str) \
88 return scope.engine->throwError(QString::fromUtf8(str))
89
90struct Scope {
91 explicit Scope(ExecutionContext *ctx)
92 : engine(ctx->engine())
93 , mark(engine->jsStackTop)
94 {
95 }
96
97 explicit Scope(ExecutionEngine *e)
98 : engine(e)
99 , mark(engine->jsStackTop)
100 {
101 }
102
103 explicit Scope(const Managed *m)
104 : engine(m->engine())
105 , mark(engine->jsStackTop)
106 {
107 }
108
109 ~Scope() {
110#ifndef QT_NO_DEBUG
111 Q_ASSERT(engine->jsStackTop >= mark);
112// Q_ASSERT(engine->currentContext < mark);
113 memset(s: mark, c: 0, n: (engine->jsStackTop - mark)*sizeof(Value));
114#endif
115#ifdef V4_USE_VALGRIND
116 VALGRIND_MAKE_MEM_UNDEFINED(mark, (engine->jsStackLimit - mark) * sizeof(Value));
117#endif
118 engine->jsStackTop = mark;
119 }
120
121 enum AllocMode {
122 Undefined,
123 Empty,
124 /* Be careful when using Uninitialized, the stack has to be fully initialized before calling into the memory manager again */
125 Uninitialized
126 };
127 template <AllocMode mode = Undefined>
128 QML_NEARLY_ALWAYS_INLINE Value *alloc(int nValues) const
129 {
130 Value *ptr = engine->jsAlloca(nValues);
131 switch (mode) {
132 case Undefined:
133 for (int i = 0; i < nValues; ++i)
134 ptr[i] = Value::undefinedValue();
135 break;
136 case Empty:
137 for (int i = 0; i < nValues; ++i)
138 ptr[i] = Value::emptyValue();
139 break;
140 case Uninitialized:
141 break;
142 }
143 return ptr;
144 }
145 template <AllocMode mode = Undefined>
146 QML_NEARLY_ALWAYS_INLINE Value *alloc() const
147 {
148 Value *ptr = engine->jsAlloca(nValues: 1);
149 switch (mode) {
150 case Undefined:
151 *ptr = Value::undefinedValue();
152 break;
153 case Empty:
154 *ptr = Value::emptyValue();
155 break;
156 case Uninitialized:
157 break;
158 }
159 return ptr;
160 }
161
162 bool hasException() const {
163 return engine->hasException;
164 }
165
166 ExecutionEngine *engine;
167 Value *mark;
168
169private:
170 Q_DISABLE_COPY(Scope)
171};
172
173struct ScopedValue
174{
175 ScopedValue(const ScopedValue &) = default;
176 ScopedValue(ScopedValue &&) = default;
177
178 ScopedValue(const Scope &scope)
179 {
180 ptr = scope.alloc<Scope::Uninitialized>();
181 ptr->setRawValue(0);
182 }
183
184 ScopedValue(const Scope &scope, const Value &v)
185 {
186 ptr = scope.alloc<Scope::Uninitialized>();
187 *ptr = v;
188 }
189
190 ScopedValue(const Scope &scope, Heap::Base *o)
191 {
192 ptr = scope.alloc<Scope::Uninitialized>();
193 ptr->setM(o);
194 }
195
196 ScopedValue(const Scope &scope, Managed *m)
197 {
198 ptr = scope.alloc<Scope::Uninitialized>();
199 ptr->setRawValue(m->asReturnedValue());
200 }
201
202 ScopedValue(const Scope &scope, const ReturnedValue &v)
203 {
204 ptr = scope.alloc<Scope::Uninitialized>();
205 ptr->setRawValue(v);
206 }
207
208 ScopedValue &operator=(const Value &v) {
209 *ptr = v;
210 return *this;
211 }
212
213 ScopedValue &operator=(Heap::Base *o) {
214 ptr->setM(o);
215 return *this;
216 }
217
218 ScopedValue &operator=(Managed *m) {
219 *ptr = *m;
220 return *this;
221 }
222
223 ScopedValue &operator=(const ReturnedValue &v) {
224 ptr->setRawValue(v);
225 return *this;
226 }
227
228 ScopedValue &operator=(const ScopedValue &other) {
229 *ptr = *other.ptr;
230 return *this;
231 }
232
233 Value *operator->() {
234 return ptr;
235 }
236
237 const Value *operator->() const {
238 return ptr;
239 }
240
241 operator Value *() { return ptr; }
242 operator const Value &() const { return *ptr; }
243
244 Value *ptr;
245};
246
247
248struct ScopedPropertyKey
249{
250 ScopedPropertyKey(const Scope &scope)
251 {
252 ptr = reinterpret_cast<PropertyKey *>(scope.alloc<Scope::Uninitialized>());
253 *ptr = PropertyKey::invalid();
254 }
255
256 ScopedPropertyKey(const Scope &scope, const PropertyKey &v)
257 {
258 ptr = reinterpret_cast<PropertyKey *>(scope.alloc<Scope::Uninitialized>());
259 *ptr = v;
260 }
261
262 ScopedPropertyKey &operator=(const PropertyKey &other) {
263 *ptr = other;
264 return *this;
265 }
266
267 PropertyKey *operator->() {
268 return ptr;
269 }
270 operator PropertyKey() const {
271 return *ptr;
272 }
273
274 bool operator==(const PropertyKey &other) const {
275 return *ptr == other;
276 }
277 bool operator==(const ScopedPropertyKey &other) const {
278 return *ptr == *other.ptr;
279 }
280 bool operator!=(const PropertyKey &other) const {
281 return *ptr != other;
282 }
283 bool operator!=(const ScopedPropertyKey &other) const {
284 return *ptr != *other.ptr;
285 }
286
287 PropertyKey *ptr;
288};
289
290
291template<typename T>
292struct Scoped
293{
294 enum ConvertType { Convert };
295
296 QML_NEARLY_ALWAYS_INLINE void setPointer(const Managed *p) {
297 ptr->setM(p ? p->m() : nullptr);
298 }
299
300 QML_NEARLY_ALWAYS_INLINE Scoped(const Scope &scope)
301 {
302 ptr = scope.alloc<Scope::Undefined>();
303 }
304
305 QML_NEARLY_ALWAYS_INLINE Scoped(const Scope &scope, const Value &v)
306 {
307 ptr = scope.alloc<Scope::Uninitialized>();
308 setPointer(v.as<T>());
309 }
310 QML_NEARLY_ALWAYS_INLINE Scoped(const Scope &scope, Heap::Base *o)
311 {
312 Value v;
313 v = o;
314 ptr = scope.alloc<Scope::Uninitialized>();
315 setPointer(v.as<T>());
316 }
317 QML_NEARLY_ALWAYS_INLINE Scoped(const Scope &scope, const ScopedValue &v)
318 {
319 ptr = scope.alloc<Scope::Uninitialized>();
320 setPointer(v.ptr->as<T>());
321 }
322
323 QML_NEARLY_ALWAYS_INLINE Scoped(const Scope &scope, const Value &v, ConvertType)
324 {
325 ptr = scope.alloc<Scope::Uninitialized>();
326 ptr->setRawValue(value_convert<T>(scope.engine, v));
327 }
328
329 QML_NEARLY_ALWAYS_INLINE Scoped(const Scope &scope, const Value *v)
330 {
331 ptr = scope.alloc<Scope::Uninitialized>();
332 setPointer(v ? v->as<T>() : nullptr);
333 }
334
335 QML_NEARLY_ALWAYS_INLINE Scoped(const Scope &scope, T *t)
336 {
337 ptr = scope.alloc<Scope::Uninitialized>();
338 setPointer(t);
339 }
340
341 QML_NEARLY_ALWAYS_INLINE Scoped(const Scope &scope, const T *t)
342 {
343 ptr = scope.alloc<Scope::Uninitialized>();
344 setPointer(t);
345 }
346
347 QML_NEARLY_ALWAYS_INLINE Scoped(const Scope &scope, typename T::Data *t)
348 {
349 ptr = scope.alloc<Scope::Uninitialized>();
350 *ptr = t;
351 }
352
353 QML_NEARLY_ALWAYS_INLINE Scoped(const Scope &scope, const ReturnedValue &v)
354 {
355 ptr = scope.alloc<Scope::Uninitialized>();
356 setPointer(QV4::Value::fromReturnedValue(val: v).as<T>());
357 }
358
359 QML_NEARLY_ALWAYS_INLINE Scoped(const Scope &scope, const ReturnedValue &v, ConvertType)
360 {
361 ptr = scope.alloc<Scope::Uninitialized>();
362 ptr->setRawValue(value_convert<T>(scope.engine, QV4::Value::fromReturnedValue(val: v)));
363 }
364
365 Scoped<T> &operator=(Heap::Base *o) {
366 setPointer(Value::fromHeapObject(m: o).as<T>());
367 return *this;
368 }
369 Scoped<T> &operator=(typename T::Data *t) {
370 *ptr = t;
371 return *this;
372 }
373 Scoped<T> &operator=(const Value &v) {
374 setPointer(v.as<T>());
375 return *this;
376 }
377 Scoped<T> &operator=(Value *v) {
378 setPointer(v ? v->as<T>() : nullptr);
379 return *this;
380 }
381
382 Scoped<T> &operator=(const ReturnedValue &v) {
383 setPointer(QV4::Value::fromReturnedValue(val: v).as<T>());
384 return *this;
385 }
386
387 Scoped<T> &operator=(T *t) {
388 setPointer(t);
389 return *this;
390 }
391
392 operator T *() {
393 return static_cast<T *>(ptr->managed());
394 }
395 operator const Value &() const {
396 return *ptr;
397 }
398
399 T *operator->() {
400 return getPointer();
401 }
402
403 const T *operator->() const {
404 return getPointer();
405 }
406
407 explicit operator bool() const {
408 return ptr->m();
409 }
410
411 T *getPointer() {
412 return reinterpret_cast<T *>(ptr);
413 }
414
415 const T *getPointer() const {
416 return reinterpret_cast<T *>(ptr);
417 }
418
419 Value *getRef() {
420 return ptr;
421 }
422
423 QML_NEARLY_ALWAYS_INLINE ReturnedValue asReturnedValue() const {
424 return ptr->rawValue();
425 }
426
427 Value *ptr;
428};
429
430inline Value &Value::operator =(const ScopedValue &v)
431{
432 _val = v.ptr->rawValue();
433 return *this;
434}
435
436template<typename T>
437inline Value &Value::operator=(const Scoped<T> &t)
438{
439 _val = t.ptr->rawValue();
440 return *this;
441}
442
443struct ScopedProperty
444{
445 ScopedProperty(Scope &scope)
446 {
447 property = reinterpret_cast<Property*>(scope.alloc(nValues: sizeof(Property) / sizeof(Value)));
448 }
449
450 Property *operator->() { return property; }
451 operator const Property *() const { return property; }
452 operator Property *() { return property; }
453
454 Property *property;
455};
456
457}
458
459QT_END_NAMESPACE
460
461#endif
462

source code of qtdeclarative/src/qml/jsruntime/qv4scopedvalue_p.h