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()) { \
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(mark, 0, (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(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 Scope &scope)
176 {
177 ptr = scope.alloc<Scope::Uninitialized>();
178 ptr->setRawValue(0);
179 }
180
181 ScopedValue(const Scope &scope, const Value &v)
182 {
183 ptr = scope.alloc<Scope::Uninitialized>();
184 *ptr = v;
185 }
186
187 ScopedValue(const Scope &scope, Heap::Base *o)
188 {
189 ptr = scope.alloc<Scope::Uninitialized>();
190 ptr->setM(o);
191 }
192
193 ScopedValue(const Scope &scope, Managed *m)
194 {
195 ptr = scope.alloc<Scope::Uninitialized>();
196 ptr->setRawValue(m->asReturnedValue());
197 }
198
199 ScopedValue(const Scope &scope, const ReturnedValue &v)
200 {
201 ptr = scope.alloc<Scope::Uninitialized>();
202 ptr->setRawValue(v);
203 }
204
205 ScopedValue &operator=(const Value &v) {
206 *ptr = v;
207 return *this;
208 }
209
210 ScopedValue &operator=(Heap::Base *o) {
211 ptr->setM(o);
212 return *this;
213 }
214
215 ScopedValue &operator=(Managed *m) {
216 *ptr = *m;
217 return *this;
218 }
219
220 ScopedValue &operator=(const ReturnedValue &v) {
221 ptr->setRawValue(v);
222 return *this;
223 }
224
225 ScopedValue &operator=(const ScopedValue &other) {
226 *ptr = *other.ptr;
227 return *this;
228 }
229
230 Value *operator->() {
231 return ptr;
232 }
233
234 const Value *operator->() const {
235 return ptr;
236 }
237
238 operator Value *() { return ptr; }
239 operator const Value &() const { return *ptr; }
240
241 Value *ptr;
242};
243
244
245struct ScopedPropertyKey
246{
247 ScopedPropertyKey(const Scope &scope)
248 {
249 ptr = reinterpret_cast<PropertyKey *>(scope.alloc<Scope::Uninitialized>());
250 *ptr = PropertyKey::invalid();
251 }
252
253 ScopedPropertyKey(const Scope &scope, const PropertyKey &v)
254 {
255 ptr = reinterpret_cast<PropertyKey *>(scope.alloc<Scope::Uninitialized>());
256 *ptr = v;
257 }
258
259 ScopedPropertyKey &operator=(const PropertyKey &other) {
260 *ptr = other;
261 return *this;
262 }
263
264 PropertyKey *operator->() {
265 return ptr;
266 }
267 operator PropertyKey() const {
268 return *ptr;
269 }
270
271 bool operator==(const PropertyKey &other) const {
272 return *ptr == other;
273 }
274 bool operator==(const ScopedPropertyKey &other) const {
275 return *ptr == *other.ptr;
276 }
277 bool operator!=(const PropertyKey &other) const {
278 return *ptr != other;
279 }
280 bool operator!=(const ScopedPropertyKey &other) const {
281 return *ptr != *other.ptr;
282 }
283
284 PropertyKey *ptr;
285};
286
287
288template<typename T>
289struct Scoped
290{
291 enum ConvertType { Convert };
292
293 QML_NEARLY_ALWAYS_INLINE void setPointer(const Managed *p) {
294 ptr->setM(p ? p->m() : nullptr);
295 }
296
297 QML_NEARLY_ALWAYS_INLINE Scoped(const Scope &scope)
298 {
299 ptr = scope.alloc<Scope::Undefined>();
300 }
301
302 QML_NEARLY_ALWAYS_INLINE Scoped(const Scope &scope, const Value &v)
303 {
304 ptr = scope.alloc<Scope::Uninitialized>();
305 setPointer(v.as<T>());
306 }
307 QML_NEARLY_ALWAYS_INLINE Scoped(const Scope &scope, Heap::Base *o)
308 {
309 Value v;
310 v = o;
311 ptr = scope.alloc<Scope::Uninitialized>();
312 setPointer(v.as<T>());
313 }
314 QML_NEARLY_ALWAYS_INLINE Scoped(const Scope &scope, const ScopedValue &v)
315 {
316 ptr = scope.alloc<Scope::Uninitialized>();
317 setPointer(v.ptr->as<T>());
318 }
319
320 QML_NEARLY_ALWAYS_INLINE Scoped(const Scope &scope, const Value &v, ConvertType)
321 {
322 ptr = scope.alloc<Scope::Uninitialized>();
323 ptr->setRawValue(value_convert<T>(scope.engine, v));
324 }
325
326 QML_NEARLY_ALWAYS_INLINE Scoped(const Scope &scope, const Value *v)
327 {
328 ptr = scope.alloc<Scope::Uninitialized>();
329 setPointer(v ? v->as<T>() : nullptr);
330 }
331
332 QML_NEARLY_ALWAYS_INLINE Scoped(const Scope &scope, T *t)
333 {
334 ptr = scope.alloc<Scope::Uninitialized>();
335 setPointer(t);
336 }
337
338 QML_NEARLY_ALWAYS_INLINE Scoped(const Scope &scope, const T *t)
339 {
340 ptr = scope.alloc<Scope::Uninitialized>();
341 setPointer(t);
342 }
343
344 QML_NEARLY_ALWAYS_INLINE Scoped(const Scope &scope, typename T::Data *t)
345 {
346 ptr = scope.alloc<Scope::Uninitialized>();
347 *ptr = t;
348 }
349
350 QML_NEARLY_ALWAYS_INLINE Scoped(const Scope &scope, const ReturnedValue &v)
351 {
352 ptr = scope.alloc<Scope::Uninitialized>();
353 setPointer(QV4::Value::fromReturnedValue(v).as<T>());
354 }
355
356 QML_NEARLY_ALWAYS_INLINE Scoped(const Scope &scope, const ReturnedValue &v, ConvertType)
357 {
358 ptr = scope.alloc<Scope::Uninitialized>();
359 ptr->setRawValue(value_convert<T>(scope.engine, QV4::Value::fromReturnedValue(v)));
360 }
361
362 Scoped<T> &operator=(Heap::Base *o) {
363 setPointer(Value::fromHeapObject(o).as<T>());
364 return *this;
365 }
366 Scoped<T> &operator=(typename T::Data *t) {
367 *ptr = t;
368 return *this;
369 }
370 Scoped<T> &operator=(const Value &v) {
371 setPointer(v.as<T>());
372 return *this;
373 }
374 Scoped<T> &operator=(Value *v) {
375 setPointer(v ? v->as<T>() : nullptr);
376 return *this;
377 }
378
379 Scoped<T> &operator=(const ReturnedValue &v) {
380 setPointer(QV4::Value::fromReturnedValue(v).as<T>());
381 return *this;
382 }
383
384 Scoped<T> &operator=(const Scoped<T> &other) {
385 *ptr = *other.ptr;
386 return *this;
387 }
388
389 Scoped<T> &operator=(T *t) {
390 setPointer(t);
391 return *this;
392 }
393
394 operator T *() {
395 return static_cast<T *>(ptr->managed());
396 }
397 operator const Value &() const {
398 return *ptr;
399 }
400
401 T *operator->() {
402 return getPointer();
403 }
404
405 const T *operator->() const {
406 return getPointer();
407 }
408
409 explicit operator bool() const {
410 return ptr->m();
411 }
412
413 T *getPointer() {
414 return reinterpret_cast<T *>(ptr);
415 }
416
417 const T *getPointer() const {
418 return reinterpret_cast<T *>(ptr);
419 }
420
421 Value *getRef() {
422 return ptr;
423 }
424
425 QML_NEARLY_ALWAYS_INLINE ReturnedValue asReturnedValue() const {
426 return ptr->rawValue();
427 }
428
429 Value *ptr;
430};
431
432inline Value &Value::operator =(const ScopedValue &v)
433{
434 _val = v.ptr->rawValue();
435 return *this;
436}
437
438template<typename T>
439inline Value &Value::operator=(const Scoped<T> &t)
440{
441 _val = t.ptr->rawValue();
442 return *this;
443}
444
445struct ScopedProperty
446{
447 ScopedProperty(Scope &scope)
448 {
449 property = reinterpret_cast<Property*>(scope.alloc(sizeof(Property) / sizeof(Value)));
450 }
451
452 Property *operator->() { return property; }
453 operator const Property *() const { return property; }
454 operator Property *() { return property; }
455
456 Property *property;
457};
458
459}
460
461QT_END_NAMESPACE
462
463#endif
464