Qt
Internal/Contributor docs for the Qt SDK. <b>Note:</b> These are NOT official API docs; those are found <a href='https://doc.qt.io/'>here</a>.
Loading...
Searching...
No Matches
qv4serialize.cpp
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
4#include "qv4serialize_p.h"
5
6#include <private/qv4dateobject_p.h>
7#include <private/qv4objectproto_p.h>
8#include <private/qv4qobjectwrapper_p.h>
9#include <private/qv4regexp_p.h>
10#include <private/qv4regexpobject_p.h>
11#include <private/qv4sequenceobject_p.h>
12#include <private/qv4value_p.h>
13
15
16using namespace QV4;
17
18// We allow the following JavaScript types to be passed between the main and
19// the secondary thread:
20// + undefined
21// + null
22// + Boolean
23// + String
24// + Function
25// + Array
26// + "Simple" Objects
27// + Number
28// + Date
29// + RegExp
30// <quint8 type><quint24 size><data>
31
50
52{
53 return quint8(type) << 24 | (size & 0xFFFFFF);
54}
55
57{
58 return (Type)(header >> 24);
59}
60
62{
63 return header & 0xFFFFFF;
64}
65
66static inline void push(QByteArray &data, quint32 value)
67{
68 data.append((const char *)&value, sizeof(quint32));
69}
70
71static inline void push(QByteArray &data, double value)
72{
73 data.append((const char *)&value, sizeof(double));
74}
75
76static inline void push(QByteArray &data, void *ptr)
77{
78 data.append((const char *)&ptr, sizeof(void *));
79}
80
81static inline void reserve(QByteArray &data, int extra)
82{
83 data.reserve(data.size() + extra);
84}
85
86static inline quint32 popUint32(const char *&data)
87{
88 quint32 rv = *((const quint32 *)data);
89 data += sizeof(quint32);
90 return rv;
91}
92
93static inline double popDouble(const char *&data)
94{
95 double rv = *((const double *)data);
96 data += sizeof(double);
97 return rv;
98}
99
100static inline void *popPtr(const char *&data)
101{
102 void *rv = *((void *const *)data);
103 data += sizeof(void *);
104 return rv;
105}
106
107#define ALIGN(size) (((size) + 3) & ~3)
108static inline void serializeString(QByteArray &data, const QString &str, Type type)
109{
110 int length = str.size();
111 if (length > 0xFFFFFF) {
113 return;
114 }
115 int utf16size = ALIGN(length * sizeof(quint16));
116
117 reserve(data, utf16size + sizeof(quint32));
119
120 int offset = data.size();
121 data.resize(data.size() + utf16size);
122 char *buffer = data.data() + offset;
123
124 memcpy(buffer, str.constData(), length*sizeof(QChar));
125}
126
127// XXX TODO: Check that worker script is exception safe in the case of
128// serialization/deserialization failures
129
131{
132 QV4::Scope scope(engine);
133
134 if (v.isEmpty()) {
135 Q_ASSERT(!"Serialize: got empty value");
136 } else if (v.isUndefined()) {
138 } else if (v.isNull()) {
140 } else if (v.isBoolean()) {
141 push(data, valueheader(v.booleanValue() == true ? WorkerTrue : WorkerFalse));
142 } else if (v.isString()) {
143 serializeString(data, v.toQString(), WorkerString);
144 } else if (v.as<FunctionObject>()) {
145 // XXX TODO: Implement passing function objects between the main and
146 // worker scripts
148 } else if (const QV4::ArrayObject *array = v.as<ArrayObject>()) {
149 uint length = array->getLength();
150 if (length > 0xFFFFFF) {
152 return;
153 }
154 reserve(data, sizeof(quint32) + length * sizeof(quint32));
156 ScopedValue val(scope);
157 for (uint ii = 0; ii < length; ++ii)
158 serialize(data, (val = array->get(ii)), engine);
159 } else if (v.isInteger()) {
160 reserve(data, 2 * sizeof(quint32));
162 push(data, (quint32)v.integerValue());
163// } else if (v.IsUint32()) {
164// reserve(data, 2 * sizeof(quint32));
165// push(data, valueheader(WorkerUint32));
166// push(data, v.Uint32Value());
167 } else if (v.isNumber()) {
168 reserve(data, sizeof(quint32) + sizeof(double));
170 push(data, v.asDouble());
171 } else if (const QV4::DateObject *d = v.as<DateObject>()) {
172 reserve(data, sizeof(quint32) + sizeof(double));
174 push(data, d->date());
175 } else if (const RegExpObject *re = v.as<RegExpObject>()) {
176 quint32 flags = re->flags();
177 QString pattern = re->source();
178 int length = pattern.size() + 1;
179 if (length > 0xFFFFFF) {
181 return;
182 }
183 int utf16size = ALIGN(length * sizeof(quint16));
184
185 reserve(data, sizeof(quint32) + utf16size);
188
189 int offset = data.size();
190 data.resize(data.size() + utf16size);
191 char *buffer = data.data() + offset;
192
193 memcpy(buffer, pattern.constData(), length*sizeof(QChar));
194 } else if (const QObjectWrapper *qobjectWrapper = v.as<QV4::QObjectWrapper>()) {
195 // XXX TODO: Generalize passing objects between the main thread and worker scripts so
196 // that others can trivially plug in their elements.
197 if (QObject *lm = qobjectWrapper->object()) {
198 if (QObject *agent = qvariant_cast<QObject *>(lm->property("agent"))) {
199 if (QMetaObject::invokeMethod(agent, "addref")) {
201 push(data, (void *)agent);
202 return;
203 }
204 }
205 }
206 // No other QObject's are allowed to be sent
208 } else if (const Sequence *s = v.as<Sequence>()) {
209 // valid sequence. we generate a length (sequence length + 1 for the sequence type)
210 uint seqLength = ScopedValue(scope, s->get(engine->id_length()))->toUInt32();
211 uint length = seqLength + 1;
212 if (length > 0xFFFFFF) {
214 return;
215 }
216 reserve(data, sizeof(quint32) + length * sizeof(quint32));
218
219 // sequence type
222
223 ScopedValue val(scope);
224 for (uint ii = 0; ii < seqLength; ++ii)
225 serialize(data, (val = s->get(ii)), engine); // sequence elements
226
227 return;
228 } else if (const Object *o = v.as<Object>()) {
230 v, QMetaType::fromType<QUrl>(), false);
231 if (variant.userType() == QMetaType::QUrl) {
233 return;
234 }
235
236 // regular object
237 QV4::ScopedValue val(scope, v);
239 quint32 length = properties->getLength();
240 if (length > 0xFFFFFF) {
242 return;
243 }
245
246 QV4::ScopedValue s(scope);
247 for (quint32 ii = 0; ii < length; ++ii) {
248 s = properties->get(ii);
250
251 QV4::String *str = s->as<String>();
252 val = o->get(str);
253 if (scope.hasException())
254 scope.engine->catchException();
255
257 }
258 return;
259 } else {
261 }
262}
263
265{
267 VariantRef(const VariantRef &r) : obj(r.obj) { addref(); }
268 VariantRef(QObject *a) : obj(a) { addref(); }
270
272 o.addref();
273 release();
274 obj = o.obj;
275 return *this;
276 }
277
278 void addref() const
279 {
280 if (obj)
282 }
283
284 void release() const
285 {
286 if (obj)
287 QMetaObject::invokeMethod(obj, "release");
288
289 }
290
292};
293
298
300{
303
304 Scope scope(engine);
305
306 switch (type) {
307 case WorkerUndefined:
308 return QV4::Encode::undefined();
309 case WorkerNull:
310 return QV4::Encode::null();
311 case WorkerTrue:
312 return QV4::Encode(true);
313 case WorkerFalse:
314 return QV4::Encode(false);
315 case WorkerString:
316 case WorkerUrl:
317 {
319 QString qstr((const QChar *)data, size);
320 data += ALIGN(size * sizeof(quint16));
321 return (type == WorkerUrl)
323 : Encode(engine->newString(qstr));
324 }
325 case WorkerFunction:
326 Q_ASSERT(!"Unreachable");
327 break;
328 case WorkerArray:
329 {
331 ScopedArrayObject a(scope, engine->newArrayObject());
332 ScopedValue v(scope);
333 for (quint32 ii = 0; ii < size; ++ii) {
335 a->put(ii, v);
336 }
337 return a.asReturnedValue();
338 }
339 case WorkerObject:
340 {
342 ScopedObject o(scope, engine->newObject());
343 ScopedValue name(scope);
344 ScopedString n(scope);
345 ScopedValue value(scope);
346 for (quint32 ii = 0; ii < size; ++ii) {
349 n = name->asReturnedValue();
350 o->put(n, value);
351 }
352 return o.asReturnedValue();
353 }
354 case WorkerInt32:
356 case WorkerUint32:
357 return QV4::Encode(popUint32(data));
358 case WorkerNumber:
359 return QV4::Encode(popDouble(data));
360 case WorkerDate:
361 return QV4::Encode(engine->newDateObject(popDouble(data)));
362 case WorkerRegexp:
363 {
366 QString pattern = QString((const QChar *)data, length - 1);
367 data += ALIGN(length * sizeof(quint16));
368 return Encode(engine->newRegExpObject(pattern, flags));
369 }
370 case WorkerListModel:
371 {
372 QObject *agent = reinterpret_cast<QObject *>(popPtr(data));
374 // ### Find a better solution then the ugly property
375 VariantRef ref(agent);
377 QV4::ScopedValue v(scope, scope.engine->fromVariant(var));
378 QV4::ScopedString s(scope, engine->newString(QStringLiteral("__qml:hidden:ref")));
379 rv->as<Object>()->defineReadonlyProperty(s, v);
380
381 QMetaObject::invokeMethod(agent, "release");
382 agent->setProperty("engine", QVariant::fromValue(engine));
383 return rv->asReturnedValue();
384 }
385 case WorkerSequence:
386 {
387 ScopedValue value(scope);
389 quint32 seqLength = length - 1;
391 int sequenceType = value->integerValue();
392 ScopedArrayObject array(scope, engine->newArrayObject());
393 array->arrayReserve(seqLength);
394 for (quint32 ii = 0; ii < seqLength; ++ii) {
396 array->arrayPut(ii, value);
397 }
398 array->setArrayLengthUnchecked(seqLength);
399 QVariant seqVariant = QV4::SequencePrototype::toVariant(array, QMetaType(sequenceType));
401 }
402 }
403 Q_ASSERT(!"Unreachable");
404 return QV4::Encode::undefined();
405}
406
413
415{
416 const char *stream = data.constData();
417 return deserialize(stream, engine);
418}
419
Definition main.cpp:8
\inmodule QtCore
Definition qbytearray.h:57
\inmodule QtCore
QJSValue newObject()
Creates a JavaScript object of class Object.
T fromVariant(const QVariant &value)
Returns the given value converted to the template type {T}.
Definition qjsengine.h:115
\inmodule QtCore
Definition qmetatype.h:341
\inmodule QtCore
Definition qobject.h:103
bool setProperty(const char *name, const QVariant &value)
Sets the value of the object's name property to value.
\macro QT_RESTRICTED_CAST_FROM_ASCII
Definition qstring.h:129
const QChar * constData() const
Returns a pointer to the data stored in the QString.
Definition qstring.h:1246
qsizetype size() const noexcept
Returns the number of characters in this string.
Definition qstring.h:186
\inmodule QtCore
Definition qurl.h:94
QString toString(FormattingOptions options=FormattingOptions(PrettyDecoded)) const
Returns a string representation of the URL.
Definition qurl.cpp:2831
static ReturnedValue deserialize(const QByteArray &, ExecutionEngine *)
static QByteArray serialize(const Value &, ExecutionEngine *)
\inmodule QtCore
Definition qvariant.h:65
T value() const &
Definition qvariant.h:516
int userType() const
Definition qvariant.h:339
static auto fromValue(T &&value) noexcept(std::is_nothrow_copy_constructible_v< T > &&Private::CanUseInternalSpace< T >) -> std::enable_if_t< std::conjunction_v< std::is_copy_constructible< T >, std::is_destructible< T > >, QVariant >
Definition qvariant.h:536
QString str
[2]
set reserve(20000)
Combined button and popup list for selecting options.
quint64 ReturnedValue
Scoped< String > ScopedString
static const QCssKnownValue properties[NumProperties - 1]
static QString header(const QString &name)
EGLStreamKHR stream
EGLOutputLayerEXT EGLint EGLAttrib value
[5]
static ControlElement< T > * ptr(QWidget *widget)
#define ALIGN(size, type)
#define Q_DECLARE_METATYPE(TYPE)
Definition qmetatype.h:1525
GLsizei const GLfloat * v
[13]
GLboolean GLboolean GLboolean GLboolean a
[7]
GLenum GLuint GLintptr GLsizeiptr size
[1]
GLboolean r
[2]
GLenum GLuint GLenum GLsizei length
GLint GLsizei GLsizei GLenum GLenum GLsizei void * data
GLenum GLuint buffer
GLenum type
GLbitfield flags
GLenum GLuint GLintptr offset
GLint ref
GLuint name
GLfloat n
GLhandleARB obj
[2]
GLdouble s
[6]
Definition qopenglext.h:235
GLuint GLfloat * val
GLenum array
GLubyte * pattern
#define Q_ASSERT(cond)
Definition qrandom.cpp:47
#define QStringLiteral(str)
unsigned int quint32
Definition qtypes.h:50
unsigned short quint16
Definition qtypes.h:48
int qint32
Definition qtypes.h:49
unsigned int uint
Definition qtypes.h:34
unsigned char quint8
Definition qtypes.h:46
static quint32 valueheader(Type type, quint32 size=0)
static quint32 popUint32(const char *&data)
static void reserve(QByteArray &data, int extra)
@ WorkerNumber
@ WorkerFunction
@ WorkerNull
@ WorkerString
@ WorkerUndefined
@ WorkerRegexp
@ WorkerSequence
@ WorkerTrue
@ WorkerArray
@ WorkerDate
@ WorkerListModel
@ WorkerInt32
@ WorkerUrl
@ WorkerUint32
@ WorkerObject
@ WorkerFalse
static void * popPtr(const char *&data)
static Type headertype(quint32 header)
static double popDouble(const char *&data)
static void push(QByteArray &data, quint32 value)
static quint32 headersize(quint32 header)
#define ALIGN(size)
static void serializeString(QByteArray &data, const QString &str, Type type)
QObject::connect nullptr
sem release()
QVariant variant
[1]
stack push(command1)
QJSEngine engine
[0]
static bool invokeMethod(QObject *obj, const char *member, Qt::ConnectionType, QGenericReturnArgument ret, QGenericArgument val0=QGenericArgument(nullptr), QGenericArgument val1=QGenericArgument(), QGenericArgument val2=QGenericArgument(), QGenericArgument val3=QGenericArgument(), QGenericArgument val4=QGenericArgument(), QGenericArgument val5=QGenericArgument(), QGenericArgument val6=QGenericArgument(), QGenericArgument val7=QGenericArgument(), QGenericArgument val8=QGenericArgument(), QGenericArgument val9=QGenericArgument())
\threadsafe This is an overloaded member function, provided for convenience. It differs from the abov...
static constexpr ReturnedValue undefined()
static constexpr ReturnedValue null()
QV4::ReturnedValue fromVariant(const QVariant &)
static QVariant toVariant(const QV4::Value &value, QMetaType typeHint, bool createJSValueForObjectsAndSymbols=true)
static Heap::ArrayObject * getOwnPropertyNames(ExecutionEngine *v4, const Value &o)
static ReturnedValue wrap(ExecutionEngine *engine, QObject *object)
ExecutionEngine * engine
static QVariant toVariant(const Sequence *object)
static QMetaType metaTypeForSequence(const Sequence *object)
static ReturnedValue fromVariant(QV4::ExecutionEngine *engine, const QVariant &vd)
static constexpr Value fromInt32(int i)
Definition qv4value_p.h:187
unsigned int toUInt32() const
Definition qv4value_p.h:364
const T * as() const
Definition qv4value_p.h:132
Definition moc.h:23
void release() const
VariantRef(const VariantRef &r)
QObject * obj
VariantRef(QObject *a)
VariantRef & operator=(const VariantRef &o)
void addref() const