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

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