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

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