Qt
Internal/Contributor docs for the Qt SDK. Note: These are NOT official API docs; those are found at https://doc.qt.io/
Loading...
Searching...
No Matches
qjsvalue_p.h
Go to the documentation of this file.
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// Qt-Security score:significant
4
5//
6// W A R N I N G
7// -------------
8//
9// This file is not part of the Qt API. It exists purely as an
10// implementation detail. This header file may change from version to
11// version without notice, or even be removed.
12//
13// We mean it.
14//
15
16#ifndef QJSVALUE_P_H
17#define QJSVALUE_P_H
18
19#include <qjsvalue.h>
20#include <private/qtqmlglobal_p.h>
21#include <private/qv4value_p.h>
22#include <private/qv4string_p.h>
23#include <private/qv4engine_p.h>
24#include <private/qv4mm_p.h>
25#include <private/qv4persistent_p.h>
26
27#include <QtCore/qthread.h>
28
30
32{
33 static constexpr quint64 s_tagBits = 3; // 3 bits mask
34 static constexpr quint64 s_tagMask = (1 << s_tagBits) - 1;
35
36 static constexpr quint64 s_pointerBit = 0x1;
37
38public:
39 enum class Kind {
40 Undefined = 0x0,
41 Null = 0x2,
42 IntValue = 0x4,
43 BoolValue = 0x6,
44 DoublePtr = 0x0 | s_pointerBit,
45 QV4ValuePtr = 0x2 | s_pointerBit,
46 QStringPtr = 0x4 | s_pointerBit,
47 };
48
49 static_assert(quint64(Kind::Undefined) <= s_tagMask);
50 static_assert(quint64(Kind::Null) <= s_tagMask);
51 static_assert(quint64(Kind::IntValue) <= s_tagMask);
52 static_assert(quint64(Kind::BoolValue) <= s_tagMask);
53 static_assert(quint64(Kind::DoublePtr) <= s_tagMask);
54 static_assert(quint64(Kind::QV4ValuePtr) <= s_tagMask);
55 static_assert(quint64(Kind::QStringPtr) <= s_tagMask);
56
57 static Kind tag(quint64 raw) { return Kind(raw & s_tagMask); }
58
59#if QT_POINTER_SIZE == 4
60 static void *pointer(quint64 raw)
61 {
63 return reinterpret_cast<void *>(raw >> 32);
64 }
65
66 static quint64 encodePointer(void *pointer, Kind tag)
67 {
69 return (quint64(quintptr(pointer)) << 32) | quint64(tag);
70 }
71#else
72 static constexpr quint64 s_minAlignment = 1 << s_tagBits;
73 static_assert(alignof(double) >= s_minAlignment);
74 static_assert(alignof(QV4::Value) >= s_minAlignment);
75 static_assert(alignof(QString) >= s_minAlignment);
76
77 static void *pointer(quint64 raw)
78 {
79 Q_ASSERT(quint64(tag(raw)) & s_pointerBit);
80 return reinterpret_cast<void *>(raw & ~s_tagMask);
81 }
82
83 static quint64 encodePointer(void *pointer, Kind tag)
84 {
85 Q_ASSERT(quint64(tag) & s_pointerBit);
86 return quintptr(pointer) | quint64(tag);
87 }
88#endif
89
91 {
92 return quint64(Kind::Undefined);
93 }
94
96 {
97 return quint64(Kind::Null);
98 }
99
100 static int intValue(quint64 v)
101 {
102 Q_ASSERT(tag(v) == Kind::IntValue);
103 return v >> 32;
104 }
105
106 static quint64 encode(int intValue)
107 {
108 return (quint64(intValue) << 32) | quint64(Kind::IntValue);
109 }
110
111 static quint64 encode(uint uintValue)
112 {
113 return (uintValue < uint(std::numeric_limits<int>::max()))
114 ? encode(int(uintValue))
115 : encode(double(uintValue));
116 }
117
118 static bool boolValue(quint64 v)
119 {
120 Q_ASSERT(tag(v) == Kind::BoolValue);
121 return v >> 32;
122 }
123
124 static quint64 encode(bool boolValue)
125 {
126 return (quint64(boolValue) << 32) | quint64(Kind::BoolValue);
127 }
128
129 static double *doublePtr(quint64 v)
130 {
131 Q_ASSERT(tag(v) == Kind::DoublePtr);
132 return static_cast<double *>(pointer(v));
133 }
134
135 static quint64 encode(double doubleValue)
136 {
137 return encodePointer(new double(doubleValue), Kind::DoublePtr);
138 }
139
140 static QV4::Value *qv4ValuePtr(quint64 v)
141 {
142 Q_ASSERT(tag(v) == Kind::QV4ValuePtr);
143 return static_cast<QV4::Value *>(pointer(v));
144 }
145
146 static quint64 encode(const QV4::Value &qv4Value)
147 {
148 switch (qv4Value.type()) {
149 case QV4::StaticValue::Boolean_Type:
150 return encode(qv4Value.booleanValue());
151 case QV4::StaticValue::Integer_Type:
152 return encode(qv4Value.integerValue());
153 case QV4::StaticValue::Managed_Type: {
154 auto managed = qv4Value.as<QV4::Managed>();
155 auto engine = managed->engine();
156 auto mm = engine->memoryManager;
157 QV4::Value *m = mm->m_persistentValues->allocate();
158 Q_ASSERT(m);
159 // we create a new strong reference to the heap managed object
160 // to avoid having to rescan the persistent values, we mark it here
161 QV4::WriteBarrier::markCustom(engine, [&](QV4::MarkStack *stack){
162 if constexpr (QV4::WriteBarrier::isInsertionBarrier)
163 managed->heapObject()->mark(stack);
164 });
165 *m = qv4Value;
166 return encodePointer(m, Kind::QV4ValuePtr);
167 }
168 case QV4::StaticValue::Double_Type:
169 return encode(qv4Value.doubleValue());
170 case QV4::StaticValue::Null_Type:
171 return encodeNull();
172 case QV4::StaticValue::Empty_Type:
173 Q_UNREACHABLE();
174 break;
175 case QV4::StaticValue::Undefined_Type:
176 break;
177 }
178
179 return encodeUndefined();
180 }
181
182 static QString *qStringPtr(quint64 v)
183 {
184 Q_ASSERT(tag(v) == Kind::QStringPtr);
185 return static_cast<QString *>(pointer(v));
186 }
187
188 static quint64 encode(QString stringValue)
189 {
190 return encodePointer(new QString(std::move(stringValue)), Kind::QStringPtr);
191 }
192
193 static quint64 encode(QLatin1String stringValue)
194 {
195 return encodePointer(new QString(std::move(stringValue)), Kind::QStringPtr);
196 }
197
198 static QJSValue fromReturnedValue(QV4::ReturnedValue d)
199 {
200 QJSValue result;
201 setValue(&result, QV4::Value::fromReturnedValue(d));
202 return result;
203 }
204
205 template<typename T>
206 static const T *asManagedType(const QJSValue *jsval)
207 {
208 if (tag(jsval->d) == Kind::QV4ValuePtr) {
209 if (const QV4::Value *value = qv4ValuePtr(jsval->d))
210 return value->as<T>();
211 }
212 return nullptr;
213 }
214
215 // This is a move operation and transfers ownership.
216 static QV4::Value *takeManagedValue(QJSValue *jsval)
217 {
218 if (tag(jsval->d) == Kind::QV4ValuePtr) {
219 if (QV4::Value *value = qv4ValuePtr(jsval->d)) {
220 jsval->d = encodeUndefined();
221 return value;
222 }
223 }
224 return nullptr;
225 }
226
227 static QV4::ReturnedValue asPrimitiveType(const QJSValue *jsval)
228 {
229 switch (tag(jsval->d)) {
230 case Kind::BoolValue:
231 return QV4::Encode(boolValue(jsval->d));
232 case Kind::IntValue:
233 return QV4::Encode(intValue(jsval->d));
234 case Kind::DoublePtr:
235 return QV4::Encode(*doublePtr(jsval->d));
236 case Kind::Null:
237 return QV4::Encode::null();
238 case Kind::Undefined:
240 case Kind::QStringPtr:
241 break;
242 }
243
244 return QV4::Encode::undefined();
245 }
246
247 // Beware: This only returns a non-null string if the QJSValue actually holds one.
248 // QV4::Strings are kept as managed values. Retrieve those with getValue().
249 static const QString *asQString(const QJSValue *jsval)
250 {
251 if (tag(jsval->d) == Kind::QStringPtr) {
252 if (const QString *string = qStringPtr(jsval->d))
253 return string;
254 }
255 return nullptr;
256 }
257
258 static QV4::ReturnedValue asReturnedValue(const QJSValue *jsval)
259 {
260 switch (tag(jsval->d)) {
261 case Kind::BoolValue:
262 return QV4::Encode(boolValue(jsval->d));
263 case Kind::IntValue:
264 return QV4::Encode(intValue(jsval->d));
265 case Kind::DoublePtr:
266 return QV4::Encode(*doublePtr(jsval->d));
267 case Kind::Null:
268 return QV4::Encode::null();
270 return qv4ValuePtr(jsval->d)->asReturnedValue();
271 case Kind::Undefined:
272 case Kind::QStringPtr:
273 break;
274 }
275
276 return QV4::Encode::undefined();
277 }
278
279 static void setString(QJSValue *jsval, QString s)
280 {
281 jsval->d = encode(std::move(s));
282 }
283
284 // Only use this with an existing persistent value.
285 // Ownership is transferred to the QJSValue.
286 static void adoptPersistentValue(QJSValue *jsval, QV4::Value *v)
287 {
288 jsval->d = encodePointer(v, Kind::QV4ValuePtr);
289 }
290
291 static void setValue(QJSValue *jsval, const QV4::Value &v)
292 {
293 jsval->d = encode(v);
294 }
295
296 // Moves any QString onto the V4 heap, changing the value to reflect that.
297 static void manageStringOnV4Heap(QV4::ExecutionEngine *e, QJSValue *jsval)
298 {
299 if (const QString *string = asQString(jsval)) {
300 jsval->d = encode(QV4::Value::fromHeapObject(e->newString(*string)));
301 delete string;
302 }
303 }
304
305 // Converts any QString on the fly, involving an allocation.
306 // Does not change the value.
307 static QV4::ReturnedValue convertToReturnedValue(QV4::ExecutionEngine *e,
308 const QJSValue &jsval)
309 {
310 if (const QString *string = asQString(&jsval))
311 return e->newString(*string)->asReturnedValue();
312 if (const QV4::Value *val = asManagedType<QV4::Managed>(&jsval)) {
313 if (QV4::PersistentValueStorage::getEngine(val) == e)
314 return val->asReturnedValue();
315
316 qWarning("JSValue can't be reassigned to another engine.");
317 return QV4::Encode::undefined();
318 }
319 return asPrimitiveType(&jsval);
320 }
321
322 static QV4::ExecutionEngine *engine(const QJSValue *jsval)
323 {
324 if (tag(jsval->d) == Kind::QV4ValuePtr) {
325 if (const QV4::Value *value = qv4ValuePtr(jsval->d))
326 return QV4::PersistentValueStorage::getEngine(value);
327 }
328
329 return nullptr;
330 }
331
332 static bool checkEngine(QV4::ExecutionEngine *e, const QJSValue &jsval)
333 {
334 QV4::ExecutionEngine *v4 = engine(&jsval);
335 return !v4 || v4 == e;
336 }
337
338 static void free(QJSValue *jsval)
339 {
340 switch (tag(jsval->d)) {
341 case Kind::Undefined:
342 case Kind::Null:
343 case Kind::IntValue:
344 case Kind::BoolValue:
345 return;
346 case Kind::DoublePtr:
347 delete doublePtr(jsval->d);
348 return;
349 case Kind::QStringPtr:
350 delete qStringPtr(jsval->d);
351 return;
353 break;
354 }
355
356 // We need a mutable value for free(). It needs to write to the actual memory.
357 QV4::Value *m = qv4ValuePtr(jsval->d);
358 Q_ASSERT(m); // Otherwise it would have been undefined above.
359 if (QV4::ExecutionEngine *e = QV4::PersistentValueStorage::getEngine(m)) {
360 if (QJSEngine *jsEngine = e->jsEngine()) {
361 if (jsEngine->thread() != QThread::currentThread()) {
362 QMetaObject::invokeMethod(
363 jsEngine, [m](){ QV4::PersistentValueStorage::free(m); });
364 return;
365 }
366 }
367 }
368 QV4::PersistentValueStorage::free(m);
369 }
370};
371
372QT_END_NAMESPACE
373
374#endif
friend class QJSEngine
The QJSValueIterator class provides a Java-style iterator for QJSValue.
static quint64 encode(bool boolValue)
Definition qjsvalue_p.h:124
static QJSValue fromReturnedValue(QV4::ReturnedValue d)
Definition qjsvalue_p.h:198
static void setString(QJSValue *jsval, QString s)
Definition qjsvalue_p.h:279
static bool boolValue(quint64 v)
Definition qjsvalue_p.h:118
static QV4::Value * qv4ValuePtr(quint64 v)
Definition qjsvalue_p.h:140
static int intValue(quint64 v)
Definition qjsvalue_p.h:100
static double * doublePtr(quint64 v)
Definition qjsvalue_p.h:129
static bool checkEngine(QV4::ExecutionEngine *e, const QJSValue &jsval)
Definition qjsvalue_p.h:332
static QV4::ExecutionEngine * engine(const QJSValue *jsval)
Definition qjsvalue_p.h:322
static quint64 encodePointer(void *pointer, Kind tag)
Definition qjsvalue_p.h:83
static QV4::Value * takeManagedValue(QJSValue *jsval)
Definition qjsvalue_p.h:216
static QV4::ReturnedValue asReturnedValue(const QJSValue *jsval)
Definition qjsvalue_p.h:258
static const QString * asQString(const QJSValue *jsval)
Definition qjsvalue_p.h:249
static quint64 encodeNull()
Definition qjsvalue_p.h:95
static constexpr quint64 s_minAlignment
Definition qjsvalue_p.h:72
static QString * qStringPtr(quint64 v)
Definition qjsvalue_p.h:182
static QV4::ReturnedValue convertToReturnedValue(QV4::ExecutionEngine *e, const QJSValue &jsval)
Definition qjsvalue_p.h:307
static quint64 encode(const QV4::Value &qv4Value)
Definition qjsvalue_p.h:146
static void adoptPersistentValue(QJSValue *jsval, QV4::Value *v)
Definition qjsvalue_p.h:286
static QV4::ReturnedValue asPrimitiveType(const QJSValue *jsval)
Definition qjsvalue_p.h:227
static void setValue(QJSValue *jsval, const QV4::Value &v)
Definition qjsvalue_p.h:291
static void manageStringOnV4Heap(QV4::ExecutionEngine *e, QJSValue *jsval)
Definition qjsvalue_p.h:297
static quint64 encode(int intValue)
Definition qjsvalue_p.h:106
static const T * asManagedType(const QJSValue *jsval)
Definition qjsvalue_p.h:206
static quint64 encode(double doubleValue)
Definition qjsvalue_p.h:135
static void * pointer(quint64 raw)
Definition qjsvalue_p.h:77
static quint64 encode(QString stringValue)
Definition qjsvalue_p.h:188
static quint64 encodeUndefined()
Definition qjsvalue_p.h:90
static void free(QJSValue *jsval)
Definition qjsvalue_p.h:338
static Kind tag(quint64 raw)
Definition qjsvalue_p.h:57
Combined button and popup list for selecting options.
Definition qjsvalue.h:24