aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorUlf Hermann <ulf.hermann@qt.io>2020-03-04 16:46:42 +0100
committerUlf Hermann <ulf.hermann@qt.io>2020-03-18 16:35:02 +0100
commit748411fa64412db1650e04ee7b4405b8fbc53d42 (patch)
treea3c94175c04a8465cb602d4d4deb557a37c1923d /src
parent7230005ef66f22a7ee3addff95b1e8d9060dc5a1 (diff)
Store a QV4::ReturnedValue in QJSValue
Being careful, we can now save primitive values inline. We use the heap pointer of QV4::Value as either QString* or QV4::Value* for complex types. We cannot store persistent managed QV4::Value without the double indirection as those need to be allocated in a special place. The generic QVariant case is not supported anymore. The only place where it was actually needed were the stream operators for QJSValue. Those were fundamentally broken: * A managed QJSValue saved and loaded from a stream was converted to a QVariant-type QJSValue * QVariant-type QJSValues were not callable, could not be objects or arrays, or any of the special types. * Cyclic references were forcibly broken when saving to a data stream. In general the support for saving and loading of managed types to/from a data stream was so abysmally bad that we don't lose much by dropping it. [ChangeLog][QML][Important Behavior Changes] When saving a QJSValue to a QDataStream only primitive values or strings will be retained. Support for objects and arrays was incomplete and unreliable already before. It cannot work correctly as we don't necessarily have a JavaScript heap when loading a QJSValue from a stream. Therefore, we don't have a proper place to keep any managed values. Using QVariant to keep them instead is a bad idea because QVariant cannot represent everything a QJSValue can contain. Fixes: QTBUG-75174 Change-Id: I75697670639bca8d4b1668763d7020c4cf871bda Reviewed-by: Fabian Kosmale <fabian.kosmale@qt.io>
Diffstat (limited to 'src')
-rw-r--r--src/imports/statemachine/signaltransition.cpp9
-rw-r--r--src/imports/testlib/quicktestutil.cpp6
-rw-r--r--src/particles/qquickcustomaffector.cpp2
-rw-r--r--src/particles/qquickparticleemitter.cpp2
-rw-r--r--src/particles/qquicktrailemitter.cpp11
-rw-r--r--src/qml/jsapi/qjsengine.cpp143
-rw-r--r--src/qml/jsapi/qjsengine.h10
-rw-r--r--src/qml/jsapi/qjsvalue.cpp458
-rw-r--r--src/qml/jsapi/qjsvalue.h3
-rw-r--r--src/qml/jsapi/qjsvalue_p.h223
-rw-r--r--src/qml/jsapi/qjsvalueiterator.cpp6
-rw-r--r--src/qml/jsruntime/qv4engine.cpp163
-rw-r--r--src/qml/jsruntime/qv4engine_p.h2
-rw-r--r--src/qml/jsruntime/qv4persistent.cpp4
-rw-r--r--src/qml/jsruntime/qv4persistent_p.h2
-rw-r--r--src/qml/jsruntime/qv4qmlcontext.cpp2
-rw-r--r--src/qml/jsruntime/qv4qobjectwrapper.cpp11
-rw-r--r--src/qml/qml/qqmlbinding.cpp8
-rw-r--r--src/qml/qml/qqmlboundsignal.cpp5
-rw-r--r--src/qml/qml/qqmlengine.cpp6
-rw-r--r--src/qml/qml/qqmlengine_p.h16
-rw-r--r--src/qml/qml/qqmlobjectcreator.cpp2
-rw-r--r--src/qml/qml/qqmltypewrapper.cpp4
-rw-r--r--src/qmlmodels/qqmldelegatemodel.cpp9
-rw-r--r--src/qmlmodels/qqmllistmodel.cpp13
-rw-r--r--src/qmlworkerscript/qquickworkerscript.cpp4
-rw-r--r--src/quick/items/context2d/qquickcanvasitem.cpp3
27 files changed, 509 insertions, 618 deletions
diff --git a/src/imports/statemachine/signaltransition.cpp b/src/imports/statemachine/signaltransition.cpp
index 69edaa4e48..51b2501a7b 100644
--- a/src/imports/statemachine/signaltransition.cpp
+++ b/src/imports/statemachine/signaltransition.cpp
@@ -106,15 +106,16 @@ void SignalTransition::setSignal(const QJSValue &signal)
if (m_signal.strictlyEquals(signal))
return;
- m_signal = signal;
-
QV4::ExecutionEngine *jsEngine = QQmlEngine::contextForObject(this)->engine()->handle();
QV4::Scope scope(jsEngine);
QObject *sender;
QMetaMethod signalMethod;
- QV4::ScopedValue value(scope, QJSValuePrivate::convertedToValue(jsEngine, m_signal));
+ m_signal = signal;
+ QJSValuePrivate::manageStringOnV4Heap(jsEngine, &m_signal);
+
+ QV4::ScopedValue value(scope, QJSValuePrivate::asReturnedValue(&m_signal));
// Did we get the "slot" that can be used to invoke the signal?
if (QV4::QObjectMethod *signalSlot = value->as<QV4::QObjectMethod>()) {
@@ -170,7 +171,7 @@ void SignalTransition::connectTriggered()
QV4::ExecutionEngine *jsEngine = QQmlEngine::contextForObject(this)->engine()->handle();
QV4::Scope scope(jsEngine);
- QV4::Scoped<QV4::QObjectMethod> qobjectSignal(scope, QJSValuePrivate::convertedToValue(jsEngine, m_signal));
+ QV4::Scoped<QV4::QObjectMethod> qobjectSignal(scope, QJSValuePrivate::asReturnedValue(&m_signal));
Q_ASSERT(qobjectSignal);
QMetaMethod metaMethod = target->metaObject()->method(qobjectSignal->methodIndex());
int signalIndex = QMetaObjectPrivate::signalIndex(metaMethod);
diff --git a/src/imports/testlib/quicktestutil.cpp b/src/imports/testlib/quicktestutil.cpp
index d9e6a2fba5..994c66845b 100644
--- a/src/imports/testlib/quicktestutil.cpp
+++ b/src/imports/testlib/quicktestutil.cpp
@@ -44,6 +44,7 @@
#include <QtQml/private/qqmlmetatype_p.h>
#include <QtQml/private/qv4engine_p.h>
#include <QtQml/private/qv4scopedvalue_p.h>
+#include <QtQml/private/qjsvalue_p.h>
#include <QtGui/qguiapplication.h>
#include <QtGui/qstylehints.h>
@@ -78,7 +79,7 @@ QJSValue QuickTestUtil::typeName(const QVariant &v) const
QQmlEngine *engine = qmlEngine(this);
QV4::ExecutionEngine *v4 = engine->handle();
- return QJSValue(v4, v4->newString(name)->asReturnedValue());
+ return QJSValuePrivate::fromReturnedValue(v4->newString(name)->asReturnedValue());
}
bool QuickTestUtil::compare(const QVariant &act, const QVariant &exp) const {
@@ -93,7 +94,8 @@ QJSValue QuickTestUtil::callerFile(int frameIndex) const
QVector<QV4::StackFrame> stack = v4->stackTrace(frameIndex + 2);
return (stack.size() > frameIndex + 1)
- ? QJSValue(v4, v4->newString(stack.at(frameIndex + 1).source)->asReturnedValue())
+ ? QJSValuePrivate::fromReturnedValue(
+ v4->newString(stack.at(frameIndex + 1).source)->asReturnedValue())
: QJSValue();
}
diff --git a/src/particles/qquickcustomaffector.cpp b/src/particles/qquickcustomaffector.cpp
index aa2617e64c..67f2922423 100644
--- a/src/particles/qquickcustomaffector.cpp
+++ b/src/particles/qquickcustomaffector.cpp
@@ -157,7 +157,7 @@ void QQuickCustomAffector::affectSystem(qreal dt)
const auto doAffect = [&](qreal dt) {
affectProperties(toAffect, dt);
QJSValue particles;
- QJSValuePrivate::setValue(&particles, v4, array);
+ QJSValuePrivate::setValue(&particles, array);
emit affectParticles(particles, dt);
};
diff --git a/src/particles/qquickparticleemitter.cpp b/src/particles/qquickparticleemitter.cpp
index 3e9d7c02a9..62bf83994f 100644
--- a/src/particles/qquickparticleemitter.cpp
+++ b/src/particles/qquickparticleemitter.cpp
@@ -497,7 +497,7 @@ void QQuickParticleEmitter::emitWindow(int timeStamp)
array->put(i, (v = toEmit[i]->v4Value(m_system)));
QJSValue particles;
- QJSValuePrivate::setValue(&particles, v4, array);
+ QJSValuePrivate::setValue(&particles, array);
emit emitParticles(particles);//A chance for arbitrary JS changes
}
diff --git a/src/particles/qquicktrailemitter.cpp b/src/particles/qquicktrailemitter.cpp
index 5720460bae..05afdf9d1f 100644
--- a/src/particles/qquicktrailemitter.cpp
+++ b/src/particles/qquicktrailemitter.cpp
@@ -278,11 +278,14 @@ void QQuickTrailEmitter::emitWindow(int timeStamp)
array->put(i, (v = toEmit[i]->v4Value(m_system)));
QJSValue particles;
- QJSValuePrivate::setValue(&particles, v4, array);
- if (isEmitFollowConnected())
- emit emitFollowParticles(particles, QJSValue(v4, d->v4Value(m_system)));//A chance for many arbitrary JS changes
- else if (isEmitConnected())
+ QJSValuePrivate::setValue(&particles, array);
+ if (isEmitFollowConnected()) {
+ //A chance for many arbitrary JS changes
+ emit emitFollowParticles(
+ particles, QJSValuePrivate::fromReturnedValue(d->v4Value(m_system)));
+ } else if (isEmitConnected()) {
emit emitParticles(particles);//A chance for arbitrary JS changes
+ }
}
m_lastEmission[d->index] = pt;
}
diff --git a/src/qml/jsapi/qjsengine.cpp b/src/qml/jsapi/qjsengine.cpp
index 6946a64d11..65b65f1b21 100644
--- a/src/qml/jsapi/qjsengine.cpp
+++ b/src/qml/jsapi/qjsengine.cpp
@@ -451,10 +451,7 @@ void QJSEngine::installExtensions(QJSEngine::Extensions extensions, const QJSVal
}
QV4::Scope scope(m_v4Engine);
- QV4::ScopedObject obj(scope);
- QV4::Value *val = QJSValuePrivate::getValue(&object);
- if (val)
- obj = val;
+ QV4::ScopedObject obj(scope, QJSValuePrivate::asReturnedValue(&object));
if (!obj)
obj = scope.engine->globalObject;
@@ -548,9 +545,7 @@ QJSValue QJSEngine::evaluate(const QString& program, const QString& fileName, in
if (v4->isInterrupted.loadAcquire())
result = v4->newErrorObject(QStringLiteral("Interrupted"));
- QJSValue retval(v4, result->asReturnedValue());
-
- return retval;
+ return QJSValuePrivate::fromReturnedValue(result->asReturnedValue());
}
/*!
@@ -578,18 +573,17 @@ QJSValue QJSEngine::importModule(const QString &fileName)
const QUrl url = urlForFileName(QFileInfo(fileName).canonicalFilePath());
auto moduleUnit = m_v4Engine->loadModule(url);
if (m_v4Engine->hasException)
- return QJSValue(m_v4Engine, m_v4Engine->catchException());
+ return QJSValuePrivate::fromReturnedValue(m_v4Engine->catchException());
QV4::Scope scope(m_v4Engine);
QV4::Scoped<QV4::Module> moduleNamespace(scope, moduleUnit->instantiate(m_v4Engine));
if (m_v4Engine->hasException)
- return QJSValue(m_v4Engine, m_v4Engine->catchException());
+ return QJSValuePrivate::fromReturnedValue(m_v4Engine->catchException());
moduleUnit->evaluate();
if (!m_v4Engine->isInterrupted.loadAcquire())
- return QJSValue(m_v4Engine, moduleNamespace->asReturnedValue());
+ return QJSValuePrivate::fromReturnedValue(moduleNamespace->asReturnedValue());
- return QJSValue(
- m_v4Engine,
+ return QJSValuePrivate::fromReturnedValue(
m_v4Engine->newErrorObject(QStringLiteral("Interrupted"))->asReturnedValue());
}
@@ -605,7 +599,7 @@ QJSValue QJSEngine::newObject()
{
QV4::Scope scope(m_v4Engine);
QV4::ScopedValue v(scope, m_v4Engine->newObject());
- return QJSValue(m_v4Engine, v->asReturnedValue());
+ return QJSValuePrivate::fromReturnedValue(v->asReturnedValue());
}
/*!
@@ -647,7 +641,7 @@ QJSValue QJSEngine::newErrorObject(QJSValue::ErrorType errorType, const QString
case QJSValue::NoError:
return QJSValue::UndefinedValue;
}
- return QJSValue(m_v4Engine, error->asReturnedValue());
+ return QJSValuePrivate::fromReturnedValue(error->asReturnedValue());
}
/*!
@@ -662,7 +656,7 @@ QJSValue QJSEngine::newArray(uint length)
if (length < 0x1000)
array->arrayReserve(length);
array->setArrayLengthUnchecked(length);
- return QJSValue(m_v4Engine, array.asReturnedValue());
+ return QJSValuePrivate::fromReturnedValue(array.asReturnedValue());
}
/*!
@@ -695,7 +689,7 @@ QJSValue QJSEngine::newQObject(QObject *object)
QQmlEngine::setObjectOwnership(object, QQmlEngine::JavaScriptOwnership);
}
QV4::ScopedValue v(scope, QV4::QObjectWrapper::wrap(v4, object));
- return QJSValue(v4, v->asReturnedValue());
+ return QJSValuePrivate::fromReturnedValue(v->asReturnedValue());
}
/*!
@@ -716,7 +710,7 @@ QJSValue QJSEngine::newQMetaObject(const QMetaObject* metaObject) {
QV4::ExecutionEngine *v4 = m_v4Engine;
QV4::Scope scope(v4);
QV4::ScopedValue v(scope, QV4::QMetaObjectWrapper::create(v4, metaObject));
- return QJSValue(v4, v->asReturnedValue());
+ return QJSValuePrivate::fromReturnedValue(v->asReturnedValue());
}
/*! \fn template <typename T> QJSValue QJSEngine::newQMetaObject()
@@ -743,7 +737,7 @@ QJSValue QJSEngine::globalObject() const
{
QV4::Scope scope(m_v4Engine);
QV4::ScopedValue v(scope, m_v4Engine->globalObject);
- return QJSValue(m_v4Engine, v->asReturnedValue());
+ return QJSValuePrivate::fromReturnedValue(v->asReturnedValue());
}
/*!
@@ -754,7 +748,7 @@ QJSValue QJSEngine::create(int type, const void *ptr)
{
QV4::Scope scope(m_v4Engine);
QV4::ScopedValue v(scope, scope.engine->metaTypeToJS(type, ptr));
- return QJSValue(m_v4Engine, v->asReturnedValue());
+ return QJSValuePrivate::fromReturnedValue(v->asReturnedValue());
}
/*!
@@ -763,118 +757,57 @@ QJSValue QJSEngine::create(int type, const void *ptr)
*/
bool QJSEngine::convertV2(const QJSValue &value, int type, void *ptr)
{
- QV4::ExecutionEngine *v4 = QJSValuePrivate::engine(&value);
- QV4::Value scratch;
- QV4::Value *val = QJSValuePrivate::valueForData(&value, &scratch);
- if (v4) {
- QV4::Scope scope(v4);
- QV4::ScopedValue v(scope, *val);
- return scope.engine->metaTypeFromJS(v, type, ptr);
- }
-
- if (!val) {
- QVariant *variant = QJSValuePrivate::getVariant(&value);
- Q_ASSERT(variant);
-
- if (variant->userType() == QMetaType::QString) {
- QString string = variant->toString();
- // have a string based value without engine. Do conversion manually
- if (type == QMetaType::Bool) {
- *reinterpret_cast<bool*>(ptr) = string.length() != 0;
- return true;
- }
- if (type == QMetaType::QString) {
- *reinterpret_cast<QString*>(ptr) = string;
- return true;
- }
- double d = QV4::RuntimeHelpers::stringToNumber(string);
- switch (type) {
- case QMetaType::Int:
- *reinterpret_cast<int*>(ptr) = QV4::Value::toInt32(d);
- return true;
- case QMetaType::UInt:
- *reinterpret_cast<uint*>(ptr) = QV4::Value::toUInt32(d);
- return true;
- case QMetaType::LongLong:
- *reinterpret_cast<qlonglong*>(ptr) = QV4::Value::toInteger(d);
- return true;
- case QMetaType::ULongLong:
- *reinterpret_cast<qulonglong*>(ptr) = QV4::Value::toInteger(d);
- return true;
- case QMetaType::Double:
- *reinterpret_cast<double*>(ptr) = d;
- return true;
- case QMetaType::Float:
- *reinterpret_cast<float*>(ptr) = d;
- return true;
- case QMetaType::Short:
- *reinterpret_cast<short*>(ptr) = QV4::Value::toInt32(d);
- return true;
- case QMetaType::UShort:
- *reinterpret_cast<unsigned short*>(ptr) = QV4::Value::toUInt32(d);
- return true;
- case QMetaType::Char:
- *reinterpret_cast<char*>(ptr) = QV4::Value::toInt32(d);
- return true;
- case QMetaType::UChar:
- *reinterpret_cast<unsigned char*>(ptr) = QV4::Value::toUInt32(d);
- return true;
- case QMetaType::QChar:
- *reinterpret_cast<QChar*>(ptr) = QV4::Value::toUInt32(d);
- return true;
- default:
- return false;
- }
- } else {
- return QMetaType::convert(&variant->data_ptr(), variant->userType(), ptr, type);
+ if (const QString *string = QJSValuePrivate::asQString(&value)) {
+ // have a string based value without engine. Do conversion manually
+ if (type == QMetaType::Bool) {
+ *reinterpret_cast<bool*>(ptr) = string->length() != 0;
+ return true;
}
- }
-
- Q_ASSERT(val);
-
- switch (type) {
- case QMetaType::Bool:
- *reinterpret_cast<bool*>(ptr) = val->toBoolean();
+ if (type == QMetaType::QString) {
+ *reinterpret_cast<QString*>(ptr) = *string;
return true;
+ }
+ double d = QV4::RuntimeHelpers::stringToNumber(*string);
+ switch (type) {
case QMetaType::Int:
- *reinterpret_cast<int*>(ptr) = val->toInt32();
+ *reinterpret_cast<int*>(ptr) = QV4::Value::toInt32(d);
return true;
case QMetaType::UInt:
- *reinterpret_cast<uint*>(ptr) = val->toUInt32();
+ *reinterpret_cast<uint*>(ptr) = QV4::Value::toUInt32(d);
return true;
case QMetaType::LongLong:
- *reinterpret_cast<qlonglong*>(ptr) = val->toInteger();
+ *reinterpret_cast<qlonglong*>(ptr) = QV4::Value::toInteger(d);
return true;
case QMetaType::ULongLong:
- *reinterpret_cast<qulonglong*>(ptr) = val->toInteger();
+ *reinterpret_cast<qulonglong*>(ptr) = QV4::Value::toInteger(d);
return true;
case QMetaType::Double:
- *reinterpret_cast<double*>(ptr) = val->toNumber();
- return true;
- case QMetaType::QString:
- *reinterpret_cast<QString*>(ptr) = val->toQStringNoThrow();
+ *reinterpret_cast<double*>(ptr) = d;
return true;
case QMetaType::Float:
- *reinterpret_cast<float*>(ptr) = val->toNumber();
+ *reinterpret_cast<float*>(ptr) = d;
return true;
case QMetaType::Short:
- *reinterpret_cast<short*>(ptr) = val->toInt32();
+ *reinterpret_cast<short*>(ptr) = QV4::Value::toInt32(d);
return true;
case QMetaType::UShort:
- *reinterpret_cast<unsigned short*>(ptr) = val->toUInt16();
+ *reinterpret_cast<unsigned short*>(ptr) = QV4::Value::toUInt32(d);
return true;
case QMetaType::Char:
- *reinterpret_cast<char*>(ptr) = val->toInt32();
+ *reinterpret_cast<char*>(ptr) = QV4::Value::toInt32(d);
return true;
case QMetaType::UChar:
- *reinterpret_cast<unsigned char*>(ptr) = val->toUInt16();
+ *reinterpret_cast<unsigned char*>(ptr) = QV4::Value::toUInt32(d);
return true;
case QMetaType::QChar:
- *reinterpret_cast<QChar*>(ptr) = val->toUInt16();
+ *reinterpret_cast<QChar*>(ptr) = QV4::Value::toUInt32(d);
return true;
default:
return false;
+ }
}
+
+ return QV4::ExecutionEngine::metaTypeFromJS(QJSValuePrivate::asReturnedValue(&value), type, ptr);
}
/*! \fn template <typename T> QJSValue QJSEngine::toScriptValue(const T &value)
@@ -991,7 +924,7 @@ void QJSEngine::throwError(QJSValue::ErrorType errorType, const QString &message
{
QV4::Scope scope(m_v4Engine);
QJSValue error = newErrorObject(errorType, message);
- QV4::ScopedObject e(scope, QJSValuePrivate::getValue(&error));
+ QV4::ScopedObject e(scope, QJSValuePrivate::asReturnedValue(&error));
if (!e)
return;
m_v4Engine->throwError(e);
diff --git a/src/qml/jsapi/qjsengine.h b/src/qml/jsapi/qjsengine.h
index 31229e1f20..16919454e7 100644
--- a/src/qml/jsapi/qjsengine.h
+++ b/src/qml/jsapi/qjsengine.h
@@ -133,7 +133,8 @@ private:
static bool convertV2(const QJSValue &value, int type, void *ptr);
- friend inline bool qjsvalue_cast_helper(const QJSValue &, int, void *);
+ template<typename T>
+ friend inline T qjsvalue_cast(const QJSValue &);
protected:
QJSEngine(QJSEnginePrivate &dd, QObject *parent = nullptr);
@@ -146,18 +147,13 @@ private:
Q_DECLARE_OPERATORS_FOR_FLAGS(QJSEngine::Extensions)
-inline bool qjsvalue_cast_helper(const QJSValue &value, int type, void *ptr)
-{
- return QJSEngine::convertV2(value, type, ptr);
-}
-
template<typename T>
T qjsvalue_cast(const QJSValue &value)
{
T t;
const int id = qMetaTypeId<T>();
- if (qjsvalue_cast_helper(value, id, &t))
+ if (QJSEngine::convertV2(value, id, &t))
return t;
else if (value.isVariant())
return qvariant_cast<T>(value.toVariant());
diff --git a/src/qml/jsapi/qjsvalue.cpp b/src/qml/jsapi/qjsvalue.cpp
index 6e632b56b2..1122700334 100644
--- a/src/qml/jsapi/qjsvalue.cpp
+++ b/src/qml/jsapi/qjsvalue.cpp
@@ -191,41 +191,29 @@ using namespace QV4;
/*!
Constructs a new QJSValue with a boolean \a value.
*/
-QJSValue::QJSValue(bool value)
+QJSValue::QJSValue(bool value) : d(QV4::Encode(value))
{
- QJSValuePrivate::setVariant(this, QVariant(value));
-}
-
-/*!
- \internal
-*/
-QJSValue::QJSValue(ExecutionEngine *e, quint64 val)
-{
- QJSValuePrivate::setValue(this, e, val);
}
/*!
Constructs a new QJSValue with a number \a value.
*/
-QJSValue::QJSValue(int value)
+QJSValue::QJSValue(int value) : d(QV4::Encode(value))
{
- QJSValuePrivate::setVariant(this, QVariant(value));
}
/*!
Constructs a new QJSValue with a number \a value.
*/
-QJSValue::QJSValue(uint value)
+QJSValue::QJSValue(uint value) : d(QV4::Encode(value))
{
- QJSValuePrivate::setVariant(this, QVariant((double)value));
}
/*!
Constructs a new QJSValue with a number \a value.
*/
-QJSValue::QJSValue(double value)
+QJSValue::QJSValue(double value) : d(QV4::Encode(value))
{
- QJSValuePrivate::setVariant(this, QVariant(value));
}
/*!
@@ -233,17 +221,14 @@ QJSValue::QJSValue(double value)
*/
QJSValue::QJSValue(const QString& value)
{
- QJSValuePrivate::setVariant(this, QVariant(value));
+ QJSValuePrivate::setString(this, QString(value));
}
/*!
Constructs a new QJSValue with a special \a value.
*/
-QJSValue::QJSValue(SpecialValue value)
- : d(0)
+QJSValue::QJSValue(SpecialValue value) : d(value == NullValue ? QV4::Encode::null() : 0)
{
- if (value == NullValue)
- QJSValuePrivate::setVariant(this, QVariant::fromValue(nullptr));
}
/*!
@@ -251,7 +236,7 @@ QJSValue::QJSValue(SpecialValue value)
*/
QJSValue::QJSValue(const QLatin1String &value)
{
- QJSValuePrivate::setVariant(this, QVariant(value));
+ QJSValuePrivate::setString(this, QString(value));
}
/*!
@@ -260,7 +245,7 @@ QJSValue::QJSValue(const QLatin1String &value)
#ifndef QT_NO_CAST_FROM_ASCII
QJSValue::QJSValue(const char *value)
{
- QJSValuePrivate::setVariant(this, QVariant(QString::fromUtf8(value)));
+ QJSValuePrivate::setString(this, QString(QString::fromUtf8(value)));
}
#endif
@@ -271,15 +256,12 @@ QJSValue::QJSValue(const char *value)
true), then only a reference to the underlying object is copied into
the new script value (i.e., the object itself is not copied).
*/
-QJSValue::QJSValue(const QJSValue& other)
- : d(0)
+QJSValue::QJSValue(const QJSValue &other) : d(0)
{
- QV4::Value *v = QJSValuePrivate::getValue(&other);
- if (v) {
- QJSValuePrivate::setValue(this, QJSValuePrivate::engine(&other), *v);
- } else if (QVariant *v = QJSValuePrivate::getVariant(&other)) {
- QJSValuePrivate::setVariant(this, *v);
- }
+ if (const QString *string = QJSValuePrivate::asQString(&other))
+ QJSValuePrivate::setString(this, *string);
+ else
+ QJSValuePrivate::setValue(this, QJSValuePrivate::asReturnedValue(&other));
}
/*!
@@ -310,11 +292,7 @@ QJSValue::~QJSValue()
*/
bool QJSValue::isBool() const
{
- QV4::Value *val = QJSValuePrivate::getValue(this);
- if (val)
- return val->isBoolean();
- QVariant *variant = QJSValuePrivate::getVariant(this);
- return variant && variant->userType() == QMetaType::Bool;
+ return QV4::Value::fromReturnedValue(d).isBoolean();
}
/*!
@@ -325,27 +303,7 @@ bool QJSValue::isBool() const
*/
bool QJSValue::isNumber() const
{
- QV4::Value *val = QJSValuePrivate::getValue(this);
- if (val)
- return val->isNumber();
- QVariant *variant = QJSValuePrivate::getVariant(this);
- if (!variant)
- return false;
-
- switch (variant->userType()) {
- case QMetaType::Double:
- case QMetaType::Int:
- case QMetaType::UInt:
- case QMetaType::Long:
- case QMetaType::ULong:
- case QMetaType::Short:
- case QMetaType::UShort:
- case QMetaType::LongLong:
- case QMetaType::ULongLong:
- return true;
- default:
- return false;
- }
+ return QV4::Value::fromReturnedValue(d).isNumber();
}
/*!
@@ -354,14 +312,7 @@ bool QJSValue::isNumber() const
*/
bool QJSValue::isNull() const
{
- QV4::Value *val = QJSValuePrivate::getValue(this);
- if (val)
- return val->isNull();
- QVariant *variant = QJSValuePrivate::getVariant(this);
- if (!variant)
- return false;
- const int type = variant->userType();
- return type == QMetaType::Nullptr || type == QMetaType::VoidStar;
+ return QV4::Value::fromReturnedValue(d).isNull();
}
/*!
@@ -372,24 +323,27 @@ bool QJSValue::isNull() const
*/
bool QJSValue::isString() const
{
- QV4::Value *val = QJSValuePrivate::getValue(this);
- if (val)
- return val->isString();
- QVariant *variant = QJSValuePrivate::getVariant(this);
- return variant && variant->userType() == QMetaType::QString;
+ if (QJSValuePrivate::asQString(this))
+ return true;
+
+ // String is managed
+ return QV4::Value::fromReturnedValue(QJSValuePrivate::asReturnedValue(this)).isString();
}
/*!
- Returns true if this QJSValue is of the primitive type Undefined;
- otherwise returns false.
+ Returns true if this QJSValue is of the primitive type Undefined or if the managed value
+ has been cleared (by deleting the engine). Otherwise returns false.
*/
bool QJSValue::isUndefined() const
{
- QV4::Value *val = QJSValuePrivate::getValue(this);
- if (val)
- return val->isUndefined();
- QVariant *variant = QJSValuePrivate::getVariant(this);
- return !variant || variant->userType() == QMetaType::UnknownType || variant->userType() == QMetaType::Void;
+ if (QJSValuePrivate::asQString(this))
+ return false;
+ QV4::Value v = QV4::Value::fromReturnedValue(QJSValuePrivate::asReturnedValue(this));
+ if (v.isUndefined())
+ return true;
+ if (!v.isManaged())
+ return false;
+ return v.managed() == nullptr;
}
/*!
@@ -400,10 +354,7 @@ bool QJSValue::isUndefined() const
*/
bool QJSValue::isError() const
{
- QV4::Value *val = QJSValuePrivate::getValue(this);
- if (!val)
- return false;
- return val->as<ErrorObject>();
+ return QJSValuePrivate::asManagedType<ErrorObject>(this);
}
/*!
@@ -415,10 +366,7 @@ bool QJSValue::isError() const
*/
QJSValue::ErrorType QJSValue::errorType() const
{
- QV4::Value *val = QJSValuePrivate::getValue(this);
- if (!val)
- return NoError;
- QV4::ErrorObject *error = val->as<ErrorObject>();
+ const QV4::ErrorObject *error = QJSValuePrivate::asManagedType<ErrorObject>(this);
if (!error)
return NoError;
switch (error->d()->errorType) {
@@ -449,10 +397,7 @@ QJSValue::ErrorType QJSValue::errorType() const
*/
bool QJSValue::isArray() const
{
- QV4::Value *val = QJSValuePrivate::getValue(this);
- if (!val)
- return false;
- return val->as<ArrayObject>();
+ return QJSValuePrivate::asManagedType<ArrayObject>(this);
}
/*!
@@ -466,10 +411,7 @@ bool QJSValue::isArray() const
*/
bool QJSValue::isObject() const
{
- QV4::Value *val = QJSValuePrivate::getValue(this);
- if (!val)
- return false;
- return val->as<QV4::Object>();
+ return QJSValuePrivate::asManagedType<QV4::Object>(this);
}
/*!
@@ -480,10 +422,7 @@ bool QJSValue::isObject() const
*/
bool QJSValue::isCallable() const
{
- QV4::Value *val = QJSValuePrivate::getValue(this);
- if (!val)
- return false;
- return val->as<FunctionObject>();
+ return QJSValuePrivate::asManagedType<FunctionObject>(this);
}
/*!
@@ -494,10 +433,7 @@ bool QJSValue::isCallable() const
*/
bool QJSValue::isVariant() const
{
- QV4::Value *val = QJSValuePrivate::getValue(this);
- if (!val)
- return false;
- return val->as<QV4::VariantObject>();
+ return QJSValuePrivate::asManagedType<QV4::VariantObject>(this);
}
/*!
@@ -514,27 +450,22 @@ bool QJSValue::isVariant() const
*/
QString QJSValue::toString() const
{
- QV4::Value scratch;
- QV4::Value *val = QJSValuePrivate::valueForData(this, &scratch);
-
- if (!val) {
- QVariant *variant = QJSValuePrivate::getVariant(this);
- Q_ASSERT(variant);
- if (variant->userType() == QMetaType::QVariantMap)
- return QStringLiteral("[object Object]");
- else if (variant->userType() == QMetaType::QVariantList) {
- const QVariantList list = variant->toList();
- QString result;
- for (int i = 0; i < list.count(); ++i) {
- if (i > 0)
- result.append(QLatin1Char(','));
- result.append(list.at(i).toString());
- }
- return result;
- }
- return variant->toString();
+ if (const QString *string = QJSValuePrivate::asQString(this))
+ return *string;
+
+ return QV4::Value::fromReturnedValue(QJSValuePrivate::asReturnedValue(this)).toQStringNoThrow();
+}
+
+template<typename T>
+T caughtResult(const QJSValue *v, T (QV4::Value::*convert)() const)
+{
+ const T result = (QV4::Value::fromReturnedValue(QJSValuePrivate::asReturnedValue(v)).*convert)();
+ QV4::ExecutionEngine *engine = QJSValuePrivate::engine(v);
+ if (engine && engine->hasException) {
+ engine->catchException();
+ return T();
}
- return val->toQStringNoThrow();
+ return result;
}
/*!
@@ -551,28 +482,10 @@ QString QJSValue::toString() const
*/
double QJSValue::toNumber() const
{
- QV4::Value scratch;
- QV4::Value *val = QJSValuePrivate::valueForData(this, &scratch);
-
- if (!val) {
- QVariant *variant = QJSValuePrivate::getVariant(this);
- Q_ASSERT(variant);
-
- if (variant->userType() == QMetaType::QString)
- return RuntimeHelpers::stringToNumber(variant->toString());
- else if (variant->canConvert<double>())
- return variant->value<double>();
- else
- return std::numeric_limits<double>::quiet_NaN();
- }
+ if (const QString *string = QJSValuePrivate::asQString(this))
+ return RuntimeHelpers::stringToNumber(*string);
- double dbl = val->toNumber();
- QV4::ExecutionEngine *engine = QJSValuePrivate::engine(this);
- if (engine && engine->hasException) {
- engine->catchException();
- return 0;
- }
- return dbl;
+ return caughtResult<double>(this, &QV4::Value::toNumber);
}
/*!
@@ -589,24 +502,10 @@ double QJSValue::toNumber() const
*/
bool QJSValue::toBool() const
{
- QV4::Value scratch;
- QV4::Value *val = QJSValuePrivate::valueForData(this, &scratch);
-
- if (!val) {
- QVariant *variant = QJSValuePrivate::getVariant(this);
- if (variant->userType() == QMetaType::QString)
- return variant->toString().length() > 0;
- else
- return variant->toBool();
- }
+ if (const QString *string = QJSValuePrivate::asQString(this))
+ return string->length() > 0;
- bool b = val->toBoolean();
- QV4::ExecutionEngine *engine = QJSValuePrivate::engine(this);
- if (engine && engine->hasException) {
- engine->catchException();
- return false;
- }
- return b;
+ return caughtResult<bool>(this, &QV4::Value::toBoolean);
}
/*!
@@ -623,24 +522,10 @@ bool QJSValue::toBool() const
*/
qint32 QJSValue::toInt() const
{
- QV4::Value scratch;
- QV4::Value *val = QJSValuePrivate::valueForData(this, &scratch);
-
- if (!val) {
- QVariant *variant = QJSValuePrivate::getVariant(this);
- if (variant->userType() == QMetaType::QString)
- return QV4::Value::toInt32(RuntimeHelpers::stringToNumber(variant->toString()));
- else
- return variant->toInt();
- }
+ if (const QString *string = QJSValuePrivate::asQString(this))
+ return QV4::Value::toInt32(RuntimeHelpers::stringToNumber(*string));
- qint32 i = val->toInt32();
- QV4::ExecutionEngine *engine = QJSValuePrivate::engine(this);
- if (engine && engine->hasException) {
- engine->catchException();
- return 0;
- }
- return i;
+ return caughtResult<qint32>(this, &QV4::Value::toInt32);
}
/*!
@@ -657,24 +542,10 @@ qint32 QJSValue::toInt() const
*/
quint32 QJSValue::toUInt() const
{
- QV4::Value scratch;
- QV4::Value *val = QJSValuePrivate::valueForData(this, &scratch);
-
- if (!val) {
- QVariant *variant = QJSValuePrivate::getVariant(this);
- if (variant->userType() == QMetaType::QString)
- return QV4::Value::toUInt32(RuntimeHelpers::stringToNumber(variant->toString()));
- else
- return variant->toUInt();
- }
+ if (const QString *string = QJSValuePrivate::asQString(this))
+ return QV4::Value::toUInt32(RuntimeHelpers::stringToNumber(*string));
- quint32 u = val->toUInt32();
- QV4::ExecutionEngine *engine = QJSValuePrivate::engine(this);
- if (engine && engine->hasException) {
- engine->catchException();
- return 0;
- }
- return u;
+ return caughtResult<quint32>(this, &QV4::Value::toUInt32);
}
/*!
@@ -701,29 +572,29 @@ quint32 QJSValue::toUInt() const
*/
QVariant QJSValue::toVariant() const
{
- QVariant *variant = QJSValuePrivate::getVariant(this);
- if (variant)
- return *variant;
-
- QV4::Value scratch;
- QV4::Value *val = QJSValuePrivate::valueForData(this, &scratch);
- Q_ASSERT(val);
-
- if (QV4::Object *o = val->as<QV4::Object>())
- return o->engine()->toVariant(*val, /*typeHint*/ -1, /*createJSValueForObjects*/ false);
-
- if (String *s = val->stringValue())
- return QVariant(s->toQString());
- if (val->isBoolean())
- return QVariant(val->booleanValue());
- if (val->isNumber()) {
- if (val->isInt32())
- return QVariant(val->integerValue());
- return QVariant(val->asDouble());
- }
- if (val->isNull())
+ if (const QString *string = QJSValuePrivate::asQString(this))
+ return QVariant(*string);
+
+ QV4::Value val = QV4::Value::fromReturnedValue(QJSValuePrivate::asReturnedValue(this));
+ if (val.isUndefined())
+ return QVariant();
+ if (val.isNull())
return QVariant(QMetaType::Nullptr, nullptr);
- Q_ASSERT(val->isUndefined());
+ if (val.isBoolean())
+ return QVariant(val.booleanValue());
+ if (val.isInt32()) // Includes doubles that can be losslessly casted to int
+ return QVariant(val.integerValue());
+ if (val.isNumber())
+ return QVariant(val.doubleValue());
+
+ Q_ASSERT(val.isManaged());
+
+ if (val.isString())
+ return QVariant(val.toQString());
+ if (QV4::Managed *m = val.as<QV4::Managed>())
+ return m->engine()->toVariant(val, /*typeHint*/ -1, /*createJSValueForObjects*/ false);
+
+ Q_ASSERT(false);
return QVariant();
}
@@ -744,11 +615,7 @@ QVariant QJSValue::toVariant() const
*/
QJSValue QJSValue::call(const QJSValueList &args) const
{
- QV4::Value *val = QJSValuePrivate::getValue(this);
- if (!val)
- return QJSValue();
-
- FunctionObject *f = val->as<FunctionObject>();
+ const FunctionObject *f = QJSValuePrivate::asManagedType<FunctionObject>(this);
if (!f)
return QJSValue();
@@ -763,7 +630,7 @@ QJSValue QJSValue::call(const QJSValueList &args) const
qWarning("QJSValue::call() failed: cannot call function with argument created in a different engine");
return QJSValue();
}
- jsCallData->args[i] = QJSValuePrivate::convertedToValue(engine, args.at(i));
+ jsCallData->args[i] = QJSValuePrivate::convertToReturnedValue(engine, args.at(i));
}
ScopedValue result(scope, f->call(jsCallData));
@@ -772,7 +639,7 @@ QJSValue QJSValue::call(const QJSValueList &args) const
if (engine->isInterrupted.loadAcquire())
result = engine->newErrorObject(QStringLiteral("Interrupted"));
- return QJSValue(engine, result->asReturnedValue());
+ return QJSValuePrivate::fromReturnedValue(result->asReturnedValue());
}
/*!
@@ -797,11 +664,7 @@ QJSValue QJSValue::call(const QJSValueList &args) const
*/
QJSValue QJSValue::callWithInstance(const QJSValue &instance, const QJSValueList &args) const
{
- QV4::Value *val = QJSValuePrivate::getValue(this);
- if (!val)
- return QJSValue();
-
- FunctionObject *f = val->as<FunctionObject>();
+ const FunctionObject *f = QJSValuePrivate::asManagedType<FunctionObject>(this);
if (!f)
return QJSValue();
@@ -815,13 +678,13 @@ QJSValue QJSValue::callWithInstance(const QJSValue &instance, const QJSValueList
}
JSCallData jsCallData(scope, args.size());
- *jsCallData->thisObject = QJSValuePrivate::convertedToValue(engine, instance);
+ *jsCallData->thisObject = QJSValuePrivate::convertToReturnedValue(engine, instance);
for (int i = 0; i < args.size(); ++i) {
if (!QJSValuePrivate::checkEngine(engine, args.at(i))) {
qWarning("QJSValue::call() failed: cannot call function with argument created in a different engine");
return QJSValue();
}
- jsCallData->args[i] = QJSValuePrivate::convertedToValue(engine, args.at(i));
+ jsCallData->args[i] = QJSValuePrivate::convertToReturnedValue(engine, args.at(i));
}
ScopedValue result(scope, f->call(jsCallData));
@@ -830,7 +693,7 @@ QJSValue QJSValue::callWithInstance(const QJSValue &instance, const QJSValueList
if (engine->isInterrupted.loadAcquire())
result = engine->newErrorObject(QStringLiteral("Interrupted"));
- return QJSValue(engine, result->asReturnedValue());
+ return QJSValuePrivate::fromReturnedValue(result->asReturnedValue());
}
/*!
@@ -853,11 +716,7 @@ QJSValue QJSValue::callWithInstance(const QJSValue &instance, const QJSValueList
*/
QJSValue QJSValue::callAsConstructor(const QJSValueList &args) const
{
- QV4::Value *val = QJSValuePrivate::getValue(this);
- if (!val)
- return QJSValue();
-
- FunctionObject *f = val->as<FunctionObject>();
+ const FunctionObject *f = QJSValuePrivate::asManagedType<FunctionObject>(this);
if (!f)
return QJSValue();
@@ -871,7 +730,7 @@ QJSValue QJSValue::callAsConstructor(const QJSValueList &args) const
qWarning("QJSValue::callAsConstructor() failed: cannot construct function with argument created in a different engine");
return QJSValue();
}
- jsCallData->args[i] = QJSValuePrivate::convertedToValue(engine, args.at(i));
+ jsCallData->args[i] = QJSValuePrivate::convertToReturnedValue(engine, args.at(i));
}
ScopedValue result(scope, f->callAsConstructor(jsCallData));
@@ -880,7 +739,7 @@ QJSValue QJSValue::callAsConstructor(const QJSValueList &args) const
if (engine->isInterrupted.loadAcquire())
result = engine->newErrorObject(QStringLiteral("Interrupted"));
- return QJSValue(engine, result->asReturnedValue());
+ return QJSValuePrivate::fromReturnedValue(result->asReturnedValue());
}
#ifdef QT_DEPRECATED
@@ -915,13 +774,13 @@ QJSValue QJSValue::prototype() const
if (!engine)
return QJSValue();
QV4::Scope scope(engine);
- ScopedObject o(scope, QJSValuePrivate::getValue(this)->as<QV4::Object>());
+ ScopedObject o(scope, QJSValuePrivate::asManagedType<QV4::Object>(this));
if (!o)
return QJSValue();
ScopedObject p(scope, o->getPrototypeOf());
if (!p)
return QJSValue(NullValue);
- return QJSValue(o->internalClass()->engine, p.asReturnedValue());
+ return QJSValuePrivate::fromReturnedValue(p.asReturnedValue());
}
/*!
@@ -942,14 +801,11 @@ void QJSValue::setPrototype(const QJSValue& prototype)
if (!engine)
return;
Scope scope(engine);
- ScopedObject o(scope, QJSValuePrivate::getValue(this));
+ ScopedObject o(scope, QJSValuePrivate::asReturnedValue(this));
if (!o)
return;
- QV4::Value scratch;
- QV4::Value *val = QJSValuePrivate::valueForData(&prototype, &scratch);
- if (!val)
- return;
- if (val->isNull()) {
+ QV4::Value val = QV4::Value::fromReturnedValue(QJSValuePrivate::asReturnedValue(&prototype));
+ if (val.isNull()) {
o->setPrototypeOf(nullptr);
return;
}
@@ -980,12 +836,11 @@ QJSValue& QJSValue::operator=(const QJSValue& other)
QJSValuePrivate::free(this);
d = 0;
- QV4::Value *v = QJSValuePrivate::getValue(&other);
- if (v) {
- QJSValuePrivate::setValue(this, QJSValuePrivate::engine(&other), *v);
- } else if (QVariant *v = QJSValuePrivate::getVariant(&other)) {
- QJSValuePrivate::setVariant(this, *v);
- }
+ if (const QString *string = QJSValuePrivate::asQString(&other))
+ QJSValuePrivate::setString(this, *string);
+ else
+ QJSValuePrivate::setValue(this, QJSValuePrivate::asReturnedValue(&other));
+
return *this;
}
@@ -1031,23 +886,17 @@ static bool js_equal(const QString &string, const QV4::Value &value)
*/
bool QJSValue::equals(const QJSValue& other) const
{
- QV4::Value s1, s2;
- QV4::Value *v = QJSValuePrivate::valueForData(this, &s1);
- QV4::Value *ov = QJSValuePrivate::valueForData(&other, &s2);
-
- if (!v) {
- QVariant *variant = QJSValuePrivate::getVariant(this);
- Q_ASSERT(variant);
- if (!ov)
- return *variant == *QJSValuePrivate::getVariant(&other);
- if (variant->userType() == QMetaType::QVariantMap || variant->userType() == QMetaType::QVariantList)
- return false;
- return js_equal(variant->toString(), *ov);
- }
- if (!ov)
- return other.equals(*this);
+ if (const QString *string = QJSValuePrivate::asQString(this)) {
+ if (const QString *otherString = QJSValuePrivate::asQString(&other))
+ return *string == *otherString;
+ return js_equal(*string, QJSValuePrivate::asReturnedValue(&other));
+ }
+
+ if (const QString *otherString = QJSValuePrivate::asQString(&other))
+ return js_equal(*otherString, QJSValuePrivate::asReturnedValue(this));
- return Runtime::CompareEqual::call(*v, *ov);
+ return Runtime::CompareEqual::call(QJSValuePrivate::asReturnedValue(this),
+ QJSValuePrivate::asReturnedValue(&other));
}
/*!
@@ -1074,25 +923,22 @@ bool QJSValue::equals(const QJSValue& other) const
*/
bool QJSValue::strictlyEquals(const QJSValue& other) const
{
- QV4::Value s1, s2;
- QV4::Value *v = QJSValuePrivate::valueForData(this, &s1);
- QV4::Value *ov = QJSValuePrivate::valueForData(&other, &s2);
-
- if (!v) {
- QVariant *variant = QJSValuePrivate::getVariant(this);
- Q_ASSERT(variant);
- if (!ov)
- return *variant == *QJSValuePrivate::getVariant(&other);
- if (variant->userType() == QMetaType::QVariantMap || variant->userType() == QMetaType::QVariantList)
- return false;
- if (String *s = ov->stringValue())
- return variant->toString() == s->toQString();
+ if (const QString *string = QJSValuePrivate::asQString(this)) {
+ if (const QString *otherString = QJSValuePrivate::asQString(&other))
+ return *string == *otherString;
+ if (const String *s = QJSValuePrivate::asManagedType<String>(&other))
+ return *string == s->toQString();
return false;
}
- if (!ov)
- return other.strictlyEquals(*this);
- return RuntimeHelpers::strictEqual(*v, *ov);
+ if (const QString *otherString = QJSValuePrivate::asQString(&other)) {
+ if (const String *s = QJSValuePrivate::asManagedType<String>(this))
+ return *otherString == s->toQString();
+ return false;
+ }
+
+ return RuntimeHelpers::strictEqual(QJSValuePrivate::asReturnedValue(this),
+ QJSValuePrivate::asReturnedValue(&other));
}
/*!
@@ -1119,7 +965,7 @@ QJSValue QJSValue::property(const QString& name) const
return QJSValue();
QV4::Scope scope(engine);
- ScopedObject o(scope, QJSValuePrivate::getValue(this));
+ ScopedObject o(scope, QJSValuePrivate::asReturnedValue(this));
if (!o)
return QJSValue();
@@ -1128,7 +974,7 @@ QJSValue QJSValue::property(const QString& name) const
if (engine->hasException)
result = engine->catchException();
- return QJSValue(engine, result->asReturnedValue());
+ return QJSValuePrivate::fromReturnedValue(result->asReturnedValue());
}
/*!
@@ -1167,14 +1013,14 @@ QJSValue QJSValue::property(quint32 arrayIndex) const
return QJSValue();
QV4::Scope scope(engine);
- ScopedObject o(scope, QJSValuePrivate::getValue(this));
+ ScopedObject o(scope, QJSValuePrivate::asReturnedValue(this));
if (!o)
return QJSValue();
QV4::ScopedValue result(scope, arrayIndex == UINT_MAX ? o->get(engine->id_uintMax()) : o->get(arrayIndex));
if (engine->hasException)
engine->catchException();
- return QJSValue(engine, result->asReturnedValue());
+ return QJSValuePrivate::fromReturnedValue(result->asReturnedValue());
}
/*!
@@ -1199,7 +1045,7 @@ void QJSValue::setProperty(const QString& name, const QJSValue& value)
return;
Scope scope(engine);
- ScopedObject o(scope, QJSValuePrivate::getValue(this));
+ ScopedObject o(scope, QJSValuePrivate::asReturnedValue(this));
if (!o)
return;
@@ -1209,7 +1055,7 @@ void QJSValue::setProperty(const QString& name, const QJSValue& value)
}
ScopedString s(scope, engine->newString(name));
- QV4::ScopedValue v(scope, QJSValuePrivate::convertedToValue(engine, value));
+ QV4::ScopedValue v(scope, QJSValuePrivate::convertToReturnedValue(engine, value));
o->put(s->toPropertyKey(), v);
if (engine->hasException)
engine->catchException();
@@ -1253,7 +1099,7 @@ void QJSValue::setProperty(quint32 arrayIndex, const QJSValue& value)
return;
Scope scope(engine);
- ScopedObject o(scope, QJSValuePrivate::getValue(this));
+ ScopedObject o(scope, QJSValuePrivate::asReturnedValue(this));
if (!o)
return;
@@ -1262,7 +1108,7 @@ void QJSValue::setProperty(quint32 arrayIndex, const QJSValue& value)
return;
}
- QV4::ScopedValue v(scope, QJSValuePrivate::convertedToValue(engine, value));
+ QV4::ScopedValue v(scope, QJSValuePrivate::convertToReturnedValue(engine, value));
PropertyKey id = arrayIndex != UINT_MAX ? PropertyKey::fromArrayIndex(arrayIndex) : engine->id_uintMax()->propertyKey();
o->put(id, v);
if (engine->hasException)
@@ -1296,7 +1142,7 @@ bool QJSValue::deleteProperty(const QString &name)
return false;
Scope scope(engine);
- ScopedObject o(scope, QJSValuePrivate::getValue(this));
+ ScopedObject o(scope, QJSValuePrivate::asReturnedValue(this));
if (!o)
return false;
@@ -1317,7 +1163,7 @@ bool QJSValue::hasProperty(const QString &name) const
return false;
Scope scope(engine);
- ScopedObject o(scope, QJSValuePrivate::getValue(this));
+ ScopedObject o(scope, QJSValuePrivate::asReturnedValue(this));
if (!o)
return false;
@@ -1338,7 +1184,7 @@ bool QJSValue::hasOwnProperty(const QString &name) const
return false;
Scope scope(engine);
- ScopedObject o(scope, QJSValuePrivate::getValue(this));
+ ScopedObject o(scope, QJSValuePrivate::asReturnedValue(this));
if (!o)
return false;
@@ -1362,7 +1208,7 @@ QObject *QJSValue::toQObject() const
if (!engine)
return nullptr;
QV4::Scope scope(engine);
- QV4::Scoped<QV4::QObjectWrapper> wrapper(scope, QJSValuePrivate::getValue(this));
+ QV4::Scoped<QV4::QObjectWrapper> wrapper(scope, QJSValuePrivate::asReturnedValue(this));
if (!wrapper)
return nullptr;
@@ -1383,7 +1229,7 @@ const QMetaObject *QJSValue::toQMetaObject() const
if (!engine)
return nullptr;
QV4::Scope scope(engine);
- QV4::Scoped<QV4::QMetaObjectWrapper> wrapper(scope, QJSValuePrivate::getValue(this));
+ QV4::Scoped<QV4::QMetaObjectWrapper> wrapper(scope, QJSValuePrivate::asReturnedValue(this));
if (!wrapper)
return nullptr;
@@ -1400,12 +1246,8 @@ const QMetaObject *QJSValue::toQMetaObject() const
*/
QDateTime QJSValue::toDateTime() const
{
- QV4::Value *val = QJSValuePrivate::getValue(this);
- if (val) {
- QV4::DateObject *date = val->as<DateObject>();
- if (date)
- return date->toQDateTime();
- }
+ if (const QV4::DateObject *date = QJSValuePrivate::asManagedType<DateObject>(this))
+ return date->toQDateTime();
return QDateTime();
}
@@ -1415,8 +1257,7 @@ QDateTime QJSValue::toDateTime() const
*/
bool QJSValue::isDate() const
{
- QV4::Value *val = QJSValuePrivate::getValue(this);
- return val && val->as<DateObject>();
+ return QJSValuePrivate::asManagedType<DateObject>(this);
}
/*!
@@ -1425,8 +1266,7 @@ bool QJSValue::isDate() const
*/
bool QJSValue::isRegExp() const
{
- QV4::Value *val = QJSValuePrivate::getValue(this);
- return val && val->as<RegExpObject>();
+ return QJSValuePrivate::asManagedType<RegExpObject>(this);
}
/*!
@@ -1440,8 +1280,7 @@ bool QJSValue::isRegExp() const
*/
bool QJSValue::isQObject() const
{
- QV4::Value *val = QJSValuePrivate::getValue(this);
- return val && val->as<QV4::QObjectWrapper>() != nullptr;
+ return QJSValuePrivate::asManagedType<QV4::QObjectWrapper>(this);
}
/*!
@@ -1454,8 +1293,7 @@ bool QJSValue::isQObject() const
*/
bool QJSValue::isQMetaObject() const
{
- QV4::Value *val = QJSValuePrivate::getValue(this);
- return val && val->as<QV4::QMetaObjectWrapper>() != nullptr;
+ return QJSValuePrivate::asManagedType<QV4::QMetaObjectWrapper>(this);
}
QT_END_NAMESPACE
diff --git a/src/qml/jsapi/qjsvalue.h b/src/qml/jsapi/qjsvalue.h
index b491080e56..091f353291 100644
--- a/src/qml/jsapi/qjsvalue.h
+++ b/src/qml/jsapi/qjsvalue.h
@@ -153,13 +153,12 @@ public:
QT_DEPRECATED QJSEngine *engine() const;
#endif
- QJSValue(QV4::ExecutionEngine *e, quint64 val);
private:
friend class QJSValuePrivate;
// force compile error, prevent QJSValue(bool) to be called
QJSValue(void *) Q_DECL_EQ_DELETE;
- mutable quintptr d;
+ quint64 d;
};
QT_END_NAMESPACE
diff --git a/src/qml/jsapi/qjsvalue_p.h b/src/qml/jsapi/qjsvalue_p.h
index 2faffffbae..5533682144 100644
--- a/src/qml/jsapi/qjsvalue_p.h
+++ b/src/qml/jsapi/qjsvalue_p.h
@@ -64,132 +64,181 @@
QT_BEGIN_NAMESPACE
+// QJSValue::d is a QV4::ReturnedValue, but we don't want to expose that in the public header.
+// We use the lower bits of the managed pointer to hide a QString* or a QV4::Value* in there.
+Q_STATIC_ASSERT(sizeof(QV4::ReturnedValue) == sizeof(quint64));
+Q_STATIC_ASSERT(alignof(QV4::Value) >= 4);
+Q_STATIC_ASSERT(alignof(QString) >= 4);
+
+enum PointerMask: quintptr {
+ IsV4Value = 0x0,
+ IsString = 0x1
+};
+
class Q_AUTOTEST_EXPORT QJSValuePrivate
{
+ static const QV4::Value *managedValue(const QV4::Value &v)
+ {
+ const quintptr m = quintptr(v.m());
+ return (m & IsString) ? nullptr : reinterpret_cast<QV4::Value *>(m);
+ }
+
+ static const QString *qstring(const QV4::Value &v)
+ {
+ const quintptr m = quintptr(v.m());
+ return (m & IsString) ? reinterpret_cast<QString *>(m & ~IsString) : nullptr;
+ }
+
+ static QV4::ReturnedValue encode(const QString &string)
+ {
+ const quintptr m = quintptr(new QString(string)) | IsString;
+ return encodeRawValue(m);
+ }
+
+ static QV4::ReturnedValue encode(const QV4::Value &managedValue)
+ {
+ QV4::Value *m = managedValue.as<QV4::Managed>()->engine()
+ ->memoryManager->m_persistentValues->allocate();
+ *m = managedValue;
+ return encodeRawValue(quintptr(m));
+ }
+
+ static QV4::ReturnedValue encodeRawValue(quintptr m)
+ {
+ return QV4::Value::fromHeapObject(reinterpret_cast<QV4::Heap::Base *>(m)).asReturnedValue();
+ }
+
+protected:
+ // Only for the test. You're not supposed to subclass QJSValuePrivate otherwise.
+ static void setRawValue(QJSValue *jsval, QV4::Value *m)
+ {
+ jsval->d = encodeRawValue(quintptr(m));
+ }
+
public:
- static inline QV4::Value *getValue(const QJSValue *jsval)
+ static QJSValue fromReturnedValue(QV4::ReturnedValue d)
{
- if (jsval->d & 3)
- return nullptr;
- return reinterpret_cast<QV4::Value *>(jsval->d);
+ QJSValue result;
+ setValue(&result, d);
+ return result;
}
- static inline QVariant *getVariant(const QJSValue *jsval)
+ template<typename T>
+ static const T *asManagedType(const QJSValue *jsval)
{
- if (jsval->d & 1)
- return reinterpret_cast<QVariant *>(jsval->d & ~3);
+ const QV4::Value v = QV4::Value::fromReturnedValue(jsval->d);
+ if (!v.isManaged())
+ return nullptr;
+ if (const QV4::Value *value = managedValue(v))
+ return value->as<T>();
return nullptr;
}
- static inline void setRawValue(QJSValue *jsval, QV4::Value *v)
+ static QV4::ReturnedValue asPrimitiveType(const QJSValue *jsval)
{
- jsval->d = reinterpret_cast<quintptr>(v);
+ const QV4::Value v = QV4::Value::fromReturnedValue(jsval->d);
+ return v.isManaged() ? QV4::Encode::undefined() : v.asReturnedValue();
}
- static inline void setVariant(QJSValue *jsval, const QVariant &v) {
- QVariant *val = new QVariant(v);
- jsval->d = reinterpret_cast<quintptr>(val) | 1;
+ // Beware: This only returns a non-null string if the QJSValue actually holds one.
+ // QV4::Strings are kept as managed values. Retrieve those with getValue().
+ static const QString *asQString(const QJSValue *jsval)
+ {
+ const QV4::Value v = QV4::Value::fromReturnedValue(jsval->d);
+ return v.isManaged() ? qstring(v) : nullptr;
}
- static inline void setValue(QJSValue *jsval, QV4::ExecutionEngine *engine, const QV4::Value &v) {
- QV4::Value *value = engine->memoryManager->m_persistentValues->allocate();
- *value = v;
- jsval->d = reinterpret_cast<quintptr>(value);
+ static QV4::ReturnedValue asReturnedValue(const QJSValue *jsval)
+ {
+ const QV4::Value v = QV4::Value::fromReturnedValue(jsval->d);
+ if (!v.isManaged())
+ return v.asReturnedValue();
+
+ if (const QV4::Value *value = managedValue(v))
+ return value->asReturnedValue();
+
+ return QV4::Encode::undefined();
}
- static inline void setValue(QJSValue *jsval, QV4::ExecutionEngine *engine, QV4::ReturnedValue v) {
- QV4::Value *value = engine->memoryManager->m_persistentValues->allocate();
- *value = v;
- jsval->d = reinterpret_cast<quintptr>(value);
+ static void setString(QJSValue *jsval, const QString &s)
+ {
+ jsval->d = encode(s);
}
- static QV4::ReturnedValue convertedToValue(QV4::ExecutionEngine *e, const QJSValue &jsval)
+ static void setValue(QJSValue *jsval, const QV4::Value &v)
{
- QV4::Value *v = getValue(&jsval);
- if (!v) {
- QVariant *variant = getVariant(&jsval);
- v = e->memoryManager->m_persistentValues->allocate();
- *v = variant ? e->fromVariant(*variant) : QV4::Encode::undefined();
- jsval.d = reinterpret_cast<quintptr>(v);
- delete variant;
+ jsval->d = v.isManaged() ? encode(v) : v.asReturnedValue();
+ }
+
+ // Moves any QString onto the V4 heap, changing the value to reflect that.
+ static void manageStringOnV4Heap(QV4::ExecutionEngine *e, QJSValue *jsval)
+ {
+ if (const QString *string = asQString(jsval)) {
+ jsval->d = encode(e->newString(*string)->asReturnedValue());
+ delete string;
}
+ }
+
+ // Converts any QString on the fly, involving an allocation.
+ // Does not change the value.
+ static QV4::ReturnedValue convertToReturnedValue(QV4::ExecutionEngine *e,
+ const QJSValue &jsval)
+ {
+ if (const QString *string = asQString(&jsval))
+ return e->newString(*string)->asReturnedValue();
+ if (const QV4::Value *val = asManagedType<QV4::Managed>(&jsval)) {
+ if (QV4::PersistentValueStorage::getEngine(val) == e)
+ return val->asReturnedValue();
- if (QV4::PersistentValueStorage::getEngine(v) != e) {
qWarning("JSValue can't be reassigned to another engine.");
return QV4::Encode::undefined();
}
-
- return v->asReturnedValue();
+ return jsval.d;
}
- static QV4::Value *valueForData(const QJSValue *jsval, QV4::Value *scratch)
+ static QV4::ExecutionEngine *engine(const QJSValue *jsval)
{
- QV4::Value *v = getValue(jsval);
- if (v)
- return v;
- v = scratch;
- QVariant *variant = getVariant(jsval);
- if (!variant) {
- *v = QV4::Encode::undefined();
- return v;
- }
-
- switch (variant->userType()) {
- case QMetaType::UnknownType:
- case QMetaType::Void:
- *v = QV4::Encode::undefined();
- break;
- case QMetaType::Nullptr:
- case QMetaType::VoidStar:
- *v = QV4::Encode::null();
- break;
- case QMetaType::Bool:
- *v = QV4::Encode(variant->toBool());
- break;
- case QMetaType::Double:
- *v = QV4::Encode(variant->toDouble());
- break;
- case QMetaType::Int:
- case QMetaType::Short:
- case QMetaType::UShort:
- case QMetaType::Char:
- case QMetaType::UChar:
- *v = QV4::Encode(variant->toInt());
- break;
- case QMetaType::UInt:
- *v = QV4::Encode(variant->toUInt());
- break;
- default:
+ const QV4::Value v = QV4::Value::fromReturnedValue(jsval->d);
+ if (!v.isManaged())
return nullptr;
- }
- return v;
- }
- static QV4::ExecutionEngine *engine(const QJSValue *jsval) {
- QV4::Value *v = getValue(jsval);
- return v ? QV4::PersistentValueStorage::getEngine(v) : nullptr;
+ if (const QV4::Value *m = managedValue(v))
+ return QV4::PersistentValueStorage::getEngine(m);
+
+ return nullptr;
}
- static inline bool checkEngine(QV4::ExecutionEngine *e, const QJSValue &jsval) {
+ static bool checkEngine(QV4::ExecutionEngine *e, const QJSValue &jsval)
+ {
QV4::ExecutionEngine *v4 = engine(&jsval);
return !v4 || v4 == e;
}
- static inline void free(QJSValue *jsval) {
- if (QV4::Value *v = QJSValuePrivate::getValue(jsval)) {
- if (QV4::ExecutionEngine *e = engine(jsval)) {
- if (QJSEngine *jsEngine = e->jsEngine()) {
- if (jsEngine->thread() != QThread::currentThread()) {
- QMetaObject::invokeMethod(
- jsEngine, [v](){ QV4::PersistentValueStorage::free(v); });
- return;
- }
+ static void free(QJSValue *jsval)
+ {
+ QV4::Value v = QV4::Value::fromReturnedValue(jsval->d);
+ if (!v.isManaged())
+ return;
+
+ if (const QString *m = qstring(v)) {
+ delete m;
+ return;
+ }
+
+ // We need a mutable value for free(). It needs to write to the actual memory.
+ Q_ASSERT(!(quintptr(v.m()) & IsString));
+ QV4::Value *m = reinterpret_cast<QV4::Value *>(v.m());
+ Q_ASSERT(m); // Otherwise it would have been undefined, that is !v.isManaged() above.
+ if (QV4::ExecutionEngine *e = QV4::PersistentValueStorage::getEngine(m)) {
+ if (QJSEngine *jsEngine = e->jsEngine()) {
+ if (jsEngine->thread() != QThread::currentThread()) {
+ QMetaObject::invokeMethod(
+ jsEngine, [m](){ QV4::PersistentValueStorage::free(m); });
+ return;
}
}
- QV4::PersistentValueStorage::free(v);
- } else if (QVariant *v = QJSValuePrivate::getVariant(jsval)) {
- delete v;
}
+ QV4::PersistentValueStorage::free(m);
}
};
diff --git a/src/qml/jsapi/qjsvalueiterator.cpp b/src/qml/jsapi/qjsvalueiterator.cpp
index 076b90c5f2..360a39aea3 100644
--- a/src/qml/jsapi/qjsvalueiterator.cpp
+++ b/src/qml/jsapi/qjsvalueiterator.cpp
@@ -58,12 +58,12 @@ void QJSValueIteratorPrivate::init(const QJSValue &v)
QV4::ExecutionEngine *e = QJSValuePrivate::engine(&v);
if (!e)
return;
- QV4::Object *o = QJSValuePrivate::getValue(&v)->objectValue();
+ const QV4::Object *o = QJSValuePrivate::asManagedType<QV4::Object>(&v);
if (!o)
return;
engine = e;
- object = o;
+ object.set(e, o->asReturnedValue());
iterator.reset(o->ownPropertyKeys(object.valueRef()));
next();
}
@@ -209,7 +209,7 @@ QJSValue QJSValueIterator::value() const
scope.engine->catchException();
return QJSValue();
}
- return QJSValue(scope.engine, val->asReturnedValue());
+ return QJSValuePrivate::fromReturnedValue(val->asReturnedValue());
}
diff --git a/src/qml/jsruntime/qv4engine.cpp b/src/qml/jsruntime/qv4engine.cpp
index 1efe09c59f..d4725ce7c2 100644
--- a/src/qml/jsruntime/qv4engine.cpp
+++ b/src/qml/jsruntime/qv4engine.cpp
@@ -165,8 +165,23 @@ static void saveJSValue(QDataStream &stream, const void *data)
if (jsv->isUndefined())
isNullOrUndefined |= 0x2;
stream << isNullOrUndefined;
- if (!isNullOrUndefined)
- reinterpret_cast<const QJSValue*>(data)->toVariant().save(stream);
+ if (!isNullOrUndefined) {
+ const QVariant v = reinterpret_cast<const QJSValue*>(data)->toVariant();
+ switch (v.userType()) {
+ case QMetaType::Bool:
+ case QMetaType::Double:
+ case QMetaType::Int:
+ case QMetaType::QString:
+ v.save(stream);
+ break;
+ default:
+ qWarning() << "QDataStream::operator<< was to save a non-trivial QJSValue."
+ << "This is not supported anymore, please stream a QVariant instead.";
+ QVariant().save(stream);
+ break;
+ }
+
+ }
}
static void restoreJSValue(QDataStream &stream, void *data)
@@ -183,7 +198,25 @@ static void restoreJSValue(QDataStream &stream, void *data)
} else {
QVariant v;
v.load(stream);
- QJSValuePrivate::setVariant(jsv, v);
+
+ switch (v.userType()) {
+ case QMetaType::Bool:
+ *jsv = QJSValue(v.toBool());
+ break;
+ case QMetaType::Double:
+ *jsv = QJSValue(v.toDouble());
+ break;
+ case QMetaType::Int:
+ *jsv = QJSValue(v.toInt());
+ break;
+ case QMetaType::QString:
+ *jsv = QJSValue(v.toString());
+ break;
+ default:
+ qWarning() << "QDataStream::operator>> to restore a non-trivial QJSValue."
+ << "This is not supported anymore, please stream a QVariant instead.";
+ break;
+ }
}
}
@@ -1428,11 +1461,9 @@ QQmlError ExecutionEngine::catchExceptionAsQmlError()
typedef QSet<QV4::Heap::Object *> V4ObjectSet;
static QVariant toVariant(QV4::ExecutionEngine *e, const QV4::Value &value, int typeHint, bool createJSValueForObjects, V4ObjectSet *visitedObjects);
-static QObject *qtObjectFromJS(QV4::ExecutionEngine *engine, const QV4::Value &value);
+static QObject *qtObjectFromJS(const QV4::Value &value);
static QVariant objectToVariant(QV4::ExecutionEngine *e, const QV4::Object *o, V4ObjectSet *visitedObjects = nullptr);
-static bool convertToNativeQObject(QV4::ExecutionEngine *e, const QV4::Value &value,
- const QByteArray &targetType,
- void **result);
+static bool convertToNativeQObject(const QV4::Value &value, const QByteArray &targetType, void **result);
static QV4::ReturnedValue variantListToJS(QV4::ExecutionEngine *v4, const QVariantList &lst);
static QV4::ReturnedValue sequentialIterableToJS(QV4::ExecutionEngine *v4, const QSequentialIterable &lst);
static QV4::ReturnedValue variantMapToJS(QV4::ExecutionEngine *v4, const QVariantMap &vmap);
@@ -1463,7 +1494,7 @@ static QVariant toVariant(QV4::ExecutionEngine *e, const QV4::Value &value, int
return QVariant::fromValue(QV4::JsonObject::toJsonValue(value));
if (typeHint == qMetaTypeId<QJSValue>())
- return QVariant::fromValue(QJSValue(e, value.asReturnedValue()));
+ return QVariant::fromValue(QJSValuePrivate::fromReturnedValue(value.asReturnedValue()));
if (value.as<QV4::Object>()) {
QV4::ScopedObject object(scope, value);
@@ -1583,7 +1614,7 @@ static QVariant toVariant(QV4::ExecutionEngine *e, const QV4::Value &value, int
}
if (createJSValueForObjects)
- return QVariant::fromValue(QJSValue(scope.engine, o->asReturnedValue()));
+ return QVariant::fromValue(QJSValuePrivate::fromReturnedValue(o->asReturnedValue()));
return objectToVariant(e, o, visitedObjects);
}
@@ -1743,8 +1774,8 @@ QV4::ReturnedValue QV4::ExecutionEngine::fromVariant(const QVariant &variant)
return QV4::Encode::null();
}
} else if (type == qMetaTypeId<QJSValue>()) {
- const QJSValue *value = reinterpret_cast<const QJSValue *>(ptr);
- return QJSValuePrivate::convertedToValue(this, *value);
+ return QJSValuePrivate::convertToReturnedValue(
+ this, *reinterpret_cast<const QJSValue *>(ptr));
} else if (type == qMetaTypeId<QList<QObject *> >()) {
// XXX Can this be made more by using Array as a prototype and implementing
// directly against QList<QObject*>?
@@ -2093,94 +2124,98 @@ void ExecutionEngine::setExtensionData(int index, Deletable *data)
// Converts a JS value to a meta-type.
// data must point to a place that can store a value of the given type.
// Returns true if conversion succeeded, false otherwise.
-bool ExecutionEngine::metaTypeFromJS(const Value *value, int type, void *data)
+bool ExecutionEngine::metaTypeFromJS(const Value &value, int type, void *data)
{
// check if it's one of the types we know
switch (QMetaType::Type(type)) {
case QMetaType::Bool:
- *reinterpret_cast<bool*>(data) = value->toBoolean();
+ *reinterpret_cast<bool*>(data) = value.toBoolean();
return true;
case QMetaType::Int:
- *reinterpret_cast<int*>(data) = value->toInt32();
+ *reinterpret_cast<int*>(data) = value.toInt32();
return true;
case QMetaType::UInt:
- *reinterpret_cast<uint*>(data) = value->toUInt32();
+ *reinterpret_cast<uint*>(data) = value.toUInt32();
return true;
case QMetaType::LongLong:
- *reinterpret_cast<qlonglong*>(data) = qlonglong(value->toInteger());
+ *reinterpret_cast<qlonglong*>(data) = qlonglong(value.toInteger());
return true;
case QMetaType::ULongLong:
- *reinterpret_cast<qulonglong*>(data) = qulonglong(value->toInteger());
+ *reinterpret_cast<qulonglong*>(data) = qulonglong(value.toInteger());
return true;
case QMetaType::Double:
- *reinterpret_cast<double*>(data) = value->toNumber();
+ *reinterpret_cast<double*>(data) = value.toNumber();
return true;
case QMetaType::QString:
- if (value->isUndefined() || value->isNull())
+ if (value.isUndefined() || value.isNull())
*reinterpret_cast<QString*>(data) = QString();
else
- *reinterpret_cast<QString*>(data) = value->toQString();
+ *reinterpret_cast<QString*>(data) = value.toQString();
return true;
case QMetaType::QByteArray:
- if (const ArrayBuffer *ab = value->as<ArrayBuffer>())
+ if (const ArrayBuffer *ab = value.as<ArrayBuffer>())
*reinterpret_cast<QByteArray*>(data) = ab->asByteArray();
else
*reinterpret_cast<QByteArray*>(data) = QByteArray();
return true;
case QMetaType::Float:
- *reinterpret_cast<float*>(data) = value->toNumber();
+ *reinterpret_cast<float*>(data) = value.toNumber();
return true;
case QMetaType::Short:
- *reinterpret_cast<short*>(data) = short(value->toInt32());
+ *reinterpret_cast<short*>(data) = short(value.toInt32());
return true;
case QMetaType::UShort:
- *reinterpret_cast<unsigned short*>(data) = value->toUInt16();
+ *reinterpret_cast<unsigned short*>(data) = value.toUInt16();
return true;
case QMetaType::Char:
- *reinterpret_cast<char*>(data) = char(value->toInt32());
+ *reinterpret_cast<char*>(data) = char(value.toInt32());
return true;
case QMetaType::UChar:
- *reinterpret_cast<unsigned char*>(data) = (unsigned char)(value->toInt32());
+ *reinterpret_cast<unsigned char*>(data) = (unsigned char)(value.toInt32());
return true;
case QMetaType::QChar:
- if (String *s = value->stringValue()) {
+ if (String *s = value.stringValue()) {
QString str = s->toQString();
*reinterpret_cast<QChar*>(data) = str.isEmpty() ? QChar() : str.at(0);
} else {
- *reinterpret_cast<QChar*>(data) = QChar(ushort(value->toUInt16()));
+ *reinterpret_cast<QChar*>(data) = QChar(ushort(value.toUInt16()));
}
return true;
case QMetaType::QDateTime:
- if (const QV4::DateObject *d = value->as<DateObject>()) {
+ if (const QV4::DateObject *d = value.as<DateObject>()) {
*reinterpret_cast<QDateTime *>(data) = d->toQDateTime();
return true;
} break;
case QMetaType::QDate:
- if (const QV4::DateObject *d = value->as<DateObject>()) {
+ if (const QV4::DateObject *d = value.as<DateObject>()) {
*reinterpret_cast<QDate *>(data) = d->toQDateTime().date();
return true;
} break;
case QMetaType::QRegExp:
- if (const QV4::RegExpObject *r = value->as<QV4::RegExpObject>()) {
+ if (const QV4::RegExpObject *r = value.as<QV4::RegExpObject>()) {
*reinterpret_cast<QRegExp *>(data) = r->toQRegExp();
return true;
} break;
#if QT_CONFIG(regularexpression)
case QMetaType::QRegularExpression:
- if (const QV4::RegExpObject *r = value->as<QV4::RegExpObject>()) {
+ if (const QV4::RegExpObject *r = value.as<QV4::RegExpObject>()) {
*reinterpret_cast<QRegularExpression *>(data) = r->toQRegularExpression();
return true;
} break;
#endif
case QMetaType::QObjectStar: {
- const QV4::QObjectWrapper *qobjectWrapper = value->as<QV4::QObjectWrapper>();
- if (qobjectWrapper || value->isNull()) {
- *reinterpret_cast<QObject* *>(data) = qtObjectFromJS(this, *value);
+ if (value.isNull()) {
+ *reinterpret_cast<QObject* *>(data) = nullptr;
return true;
- } break;
+ }
+ if (value.as<QV4::QObjectWrapper>()) {
+ *reinterpret_cast<QObject* *>(data) = qtObjectFromJS(value);
+ return true;
+ }
+ break;
}
case QMetaType::QStringList: {
- const QV4::ArrayObject *a = value->as<QV4::ArrayObject>();
+ const QV4::ArrayObject *a = value.as<QV4::ArrayObject>();
if (a) {
*reinterpret_cast<QStringList *>(data) = a->toQStringList();
return true;
@@ -2188,33 +2223,45 @@ bool ExecutionEngine::metaTypeFromJS(const Value *value, int type, void *data)
break;
}
case QMetaType::QVariantList: {
- const QV4::ArrayObject *a = value->as<QV4::ArrayObject>();
+ const QV4::ArrayObject *a = value.as<QV4::ArrayObject>();
if (a) {
- *reinterpret_cast<QVariantList *>(data) = toVariant(*a, /*typeHint*/-1, /*createJSValueForObjects*/false).toList();
+ *reinterpret_cast<QVariantList *>(data) = a->engine()->toVariant(
+ *a, /*typeHint*/-1, /*createJSValueForObjects*/false).toList();
return true;
}
break;
}
case QMetaType::QVariantMap: {
- const QV4::Object *o = value->as<QV4::Object>();
+ const QV4::Object *o = value.as<QV4::Object>();
if (o) {
- *reinterpret_cast<QVariantMap *>(data) = variantMapFromJS(o);
+ *reinterpret_cast<QVariantMap *>(data) = o->engine()->variantMapFromJS(o);
return true;
}
break;
}
case QMetaType::QVariant:
- *reinterpret_cast<QVariant*>(data) = toVariant(*value, /*typeHint*/-1, /*createJSValueForObjects*/false);
+ if (const QV4::Managed *m = value.as<QV4::Managed>())
+ *reinterpret_cast<QVariant*>(data) = m->engine()->toVariant(value, /*typeHint*/-1, /*createJSValueForObjects*/false);
+ else if (value.isNull())
+ *reinterpret_cast<QVariant*>(data) = QVariant::fromValue(nullptr);
+ else if (value.isUndefined())
+ *reinterpret_cast<QVariant*>(data) = QVariant();
+ else if (value.isBoolean())
+ *reinterpret_cast<QVariant*>(data) = QVariant(value.booleanValue());
+ else if (value.isInteger())
+ *reinterpret_cast<QVariant*>(data) = QVariant(value.integerValue());
+ else if (value.isDouble())
+ *reinterpret_cast<QVariant*>(data) = QVariant(value.doubleValue());
return true;
case QMetaType::QJsonValue:
- *reinterpret_cast<QJsonValue *>(data) = QV4::JsonObject::toJsonValue(*value);
+ *reinterpret_cast<QJsonValue *>(data) = QV4::JsonObject::toJsonValue(value);
return true;
case QMetaType::QJsonObject: {
- *reinterpret_cast<QJsonObject *>(data) = QV4::JsonObject::toJsonObject(value->as<Object>());
+ *reinterpret_cast<QJsonObject *>(data) = QV4::JsonObject::toJsonObject(value.as<Object>());
return true;
}
case QMetaType::QJsonArray: {
- const QV4::ArrayObject *a = value->as<ArrayObject>();
+ const QV4::ArrayObject *a = value.as<ArrayObject>();
if (a) {
*reinterpret_cast<QJsonArray *>(data) = JsonObject::toJsonArray(a);
return true;
@@ -2226,7 +2273,7 @@ bool ExecutionEngine::metaTypeFromJS(const Value *value, int type, void *data)
}
{
- const QQmlValueTypeWrapper *vtw = value->as<QQmlValueTypeWrapper>();
+ const QQmlValueTypeWrapper *vtw = value.as<QQmlValueTypeWrapper>();
if (vtw && vtw->typeId() == type) {
return vtw->toGadget(data);
}
@@ -2254,18 +2301,18 @@ bool ExecutionEngine::metaTypeFromJS(const Value *value, int type, void *data)
// Try to use magic; for compatibility with qjsvalue_cast.
QByteArray name = QMetaType::typeName(type);
- if (convertToNativeQObject(this, *value, name, reinterpret_cast<void* *>(data)))
+ if (convertToNativeQObject(value, name, reinterpret_cast<void* *>(data)))
return true;
- if (value->as<QV4::VariantObject>() && name.endsWith('*')) {
+ if (value.as<QV4::VariantObject>() && name.endsWith('*')) {
int valueType = QMetaType::type(name.left(name.size()-1));
- QVariant &var = value->as<QV4::VariantObject>()->d()->data();
+ QVariant &var = value.as<QV4::VariantObject>()->d()->data();
if (valueType == var.userType()) {
// We have T t, T* is requested, so return &t.
*reinterpret_cast<void* *>(data) = var.data();
return true;
- } else if (Object *o = value->objectValue()) {
+ } else if (Object *o = value.objectValue()) {
// Look in the prototype chain.
- QV4::Scope scope(this);
+ QV4::Scope scope(o->engine());
QV4::ScopedObject proto(scope, o->getPrototypeOf());
while (proto) {
bool canCast = false;
@@ -2276,7 +2323,7 @@ bool ExecutionEngine::metaTypeFromJS(const Value *value, int type, void *data)
else if (proto->as<QV4::QObjectWrapper>()) {
QByteArray className = name.left(name.size()-1);
QV4::ScopedObject p(scope, proto.getPointer());
- if (QObject *qobject = qtObjectFromJS(this, p))
+ if (QObject *qobject = qtObjectFromJS(p))
canCast = qobject->qt_metacast(className) != nullptr;
}
if (canCast) {
@@ -2290,22 +2337,22 @@ bool ExecutionEngine::metaTypeFromJS(const Value *value, int type, void *data)
proto = proto->getPrototypeOf();
}
}
- } else if (value->isNull() && name.endsWith('*')) {
+ } else if (value.isNull() && name.endsWith('*')) {
*reinterpret_cast<void* *>(data) = nullptr;
return true;
} else if (type == qMetaTypeId<QJSValue>()) {
- *reinterpret_cast<QJSValue*>(data) = QJSValue(this, value->asReturnedValue());
+ QJSValuePrivate::setValue(reinterpret_cast<QJSValue*>(data), value.asReturnedValue());
return true;
}
return false;
}
-static bool convertToNativeQObject(QV4::ExecutionEngine *e, const QV4::Value &value, const QByteArray &targetType, void **result)
+static bool convertToNativeQObject(const QV4::Value &value, const QByteArray &targetType, void **result)
{
if (!targetType.endsWith('*'))
return false;
- if (QObject *qobject = qtObjectFromJS(e, value)) {
+ if (QObject *qobject = qtObjectFromJS(value)) {
int start = targetType.startsWith("const ") ? 6 : 0;
QByteArray className = targetType.mid(start, targetType.size()-start-1);
if (void *instance = qobject->qt_metacast(className)) {
@@ -2316,12 +2363,12 @@ static bool convertToNativeQObject(QV4::ExecutionEngine *e, const QV4::Value &va
return false;
}
-static QObject *qtObjectFromJS(QV4::ExecutionEngine *engine, const QV4::Value &value)
+static QObject *qtObjectFromJS(const QV4::Value &value)
{
if (!value.isObject())
return nullptr;
- QV4::Scope scope(engine);
+ QV4::Scope scope(value.as<QV4::Managed>()->engine());
QV4::Scoped<QV4::VariantObject> v(scope, value);
if (v) {
diff --git a/src/qml/jsruntime/qv4engine_p.h b/src/qml/jsruntime/qv4engine_p.h
index efe44a324c..21971c1c23 100644
--- a/src/qml/jsruntime/qv4engine_p.h
+++ b/src/qml/jsruntime/qv4engine_p.h
@@ -648,7 +648,7 @@ public:
QVariantMap variantMapFromJS(const QV4::Object *o);
- bool metaTypeFromJS(const Value *value, int type, void *data);
+ static bool metaTypeFromJS(const Value &value, int type, void *data);
QV4::ReturnedValue metaTypeToJS(int type, const void *data);
int maxJSStackSize() const;
diff --git a/src/qml/jsruntime/qv4persistent.cpp b/src/qml/jsruntime/qv4persistent.cpp
index f4901e3e4d..dea3019ef4 100644
--- a/src/qml/jsruntime/qv4persistent.cpp
+++ b/src/qml/jsruntime/qv4persistent.cpp
@@ -64,7 +64,7 @@ struct Page {
Value values[1]; // Really kEntriesPerPage, but keep the compiler happy
};
-Page *getPage(Value *val) {
+Page *getPage(const Value *val) {
return reinterpret_cast<Page *>(reinterpret_cast<quintptr>(val) & ~((quintptr)(WTF::pageSize() - 1)));
}
@@ -245,7 +245,7 @@ void PersistentValueStorage::mark(MarkStack *markStack)
}
}
-ExecutionEngine *PersistentValueStorage::getEngine(Value *v)
+ExecutionEngine *PersistentValueStorage::getEngine(const Value *v)
{
return getPage(v)->header.engine;
}
diff --git a/src/qml/jsruntime/qv4persistent_p.h b/src/qml/jsruntime/qv4persistent_p.h
index 55e8eefcb7..79e8e50790 100644
--- a/src/qml/jsruntime/qv4persistent_p.h
+++ b/src/qml/jsruntime/qv4persistent_p.h
@@ -83,7 +83,7 @@ struct Q_QML_EXPORT PersistentValueStorage
Iterator begin() { return Iterator(firstPage, 0); }
Iterator end() { return Iterator(nullptr, 0); }
- static ExecutionEngine *getEngine(Value *v);
+ static ExecutionEngine *getEngine(const Value *v);
ExecutionEngine *engine;
void *firstPage;
diff --git a/src/qml/jsruntime/qv4qmlcontext.cpp b/src/qml/jsruntime/qv4qmlcontext.cpp
index e2d3b98ff6..4538900d21 100644
--- a/src/qml/jsruntime/qv4qmlcontext.cpp
+++ b/src/qml/jsruntime/qv4qmlcontext.cpp
@@ -241,7 +241,7 @@ ReturnedValue QQmlContextWrapper::getPropertyAndBase(const QQmlContextWrapper *r
).heapObject());
} else {
QJSValue singleton = e->singletonInstance<QJSValue>(r.type);
- QV4::ScopedObject o(scope, QJSValuePrivate::convertedToValue(v4, singleton));
+ QV4::ScopedObject o(scope, QJSValuePrivate::asReturnedValue(&singleton));
lookup->qmlContextSingletonLookup.singleton = o->d();
}
lookup->qmlContextPropertyGetter = QQmlContextWrapper::lookupSingleton;
diff --git a/src/qml/jsruntime/qv4qobjectwrapper.cpp b/src/qml/jsruntime/qv4qobjectwrapper.cpp
index 66b79aa0e8..a924fa2975 100644
--- a/src/qml/jsruntime/qv4qobjectwrapper.cpp
+++ b/src/qml/jsruntime/qv4qobjectwrapper.cpp
@@ -170,7 +170,7 @@ static QV4::ReturnedValue loadProperty(QV4::ExecutionEngine *v4, QObject *object
} else if (property.propType() == qMetaTypeId<QJSValue>()) {
QJSValue v;
property.readProperty(object, &v);
- return QJSValuePrivate::convertedToValue(v4, v);
+ return QJSValuePrivate::convertToReturnedValue(v4, v);
} else if (property.isQVariant()) {
QVariant v;
property.readProperty(object, &v);
@@ -519,7 +519,7 @@ void QObjectWrapper::setProperty(ExecutionEngine *engine, QObject *object, QQmlP
} else if (value.isUndefined() && property->propType() == QMetaType::QJsonValue) {
PROPERTY_STORE(QJsonValue, QJsonValue(QJsonValue::Undefined));
} else if (!newBinding && property->propType() == qMetaTypeId<QJSValue>()) {
- PROPERTY_STORE(QJSValue, QJSValue(scope.engine, value.asReturnedValue()));
+ PROPERTY_STORE(QJSValue, QJSValuePrivate::fromReturnedValue(value.asReturnedValue()));
} else if (value.isUndefined() && property->propType() != qMetaTypeId<QQmlScriptString>()) {
QString error = QLatin1String("Cannot assign [undefined] to ");
if (!QMetaType::typeName(property->propType()))
@@ -1775,7 +1775,8 @@ bool CallArgument::fromValue(int callType, QV4::ExecutionEngine *engine, const Q
bool queryEngine = false;
if (callType == qMetaTypeId<QJSValue>()) {
- qjsValuePtr = new (&allocData) QJSValue(scope.engine, value.asReturnedValue());
+ qjsValuePtr = new (&allocData) QJSValue;
+ QJSValuePrivate::setValue(qjsValuePtr, value.asReturnedValue());
type = qMetaTypeId<QJSValue>();
} else if (callType == QMetaType::Int) {
intValue = quint32(value.toInt32());
@@ -1932,7 +1933,9 @@ QV4::ReturnedValue CallArgument::toValue(QV4::ExecutionEngine *engine)
QV4::Scope scope(engine);
if (type == qMetaTypeId<QJSValue>()) {
- return QJSValuePrivate::convertedToValue(scope.engine, *qjsValuePtr);
+ // The QJSValue can be passed around via dataPtr()
+ QJSValuePrivate::manageStringOnV4Heap(engine, qjsValuePtr);
+ return QJSValuePrivate::asReturnedValue(qjsValuePtr);
} else if (type == QMetaType::Int) {
return QV4::Encode(int(intValue));
} else if (type == QMetaType::UInt) {
diff --git a/src/qml/qml/qqmlbinding.cpp b/src/qml/qml/qqmlbinding.cpp
index b9566d5862..59f2759c81 100644
--- a/src/qml/qml/qqmlbinding.cpp
+++ b/src/qml/qml/qqmlbinding.cpp
@@ -57,6 +57,7 @@
#include <private/qv4qobjectwrapper_p.h>
#include <private/qv4variantobject_p.h>
#include <private/qv4jscall_p.h>
+#include <private/qjsvalue_p.h>
#include <qtqml_tracepoints_p.h>
@@ -455,9 +456,10 @@ Q_NEVER_INLINE bool QQmlBinding::slowWrite(const QQmlPropertyData &core,
delayedError()->setErrorDescription(QLatin1String("Invalid use of Qt.binding() in a binding declaration."));
return false;
}
- QQmlPropertyPrivate::writeValueProperty(m_target.data(), core, valueTypeData, QVariant::fromValue(
- QJSValue(v4engine, result.asReturnedValue())),
- context(), flags);
+ QQmlPropertyPrivate::writeValueProperty(
+ m_target.data(), core, valueTypeData,
+ QVariant::fromValue(QJSValuePrivate::fromReturnedValue(result.asReturnedValue())),
+ context(), flags);
} else if (isUndefined) {
const QLatin1String typeName(QMetaType::typeName(type)
? QMetaType::typeName(type)
diff --git a/src/qml/qml/qqmlboundsignal.cpp b/src/qml/qml/qqmlboundsignal.cpp
index b347bb3829..6de4ef153e 100644
--- a/src/qml/qml/qqmlboundsignal.cpp
+++ b/src/qml/qml/qqmlboundsignal.cpp
@@ -202,10 +202,7 @@ void QQmlBoundSignalExpression::evaluate(void **a)
// for several cases (such as QVariant type and QObject-derived types)
//args[ii] = engine->metaTypeToJS(type, a[ii + 1]);
if (type == qMetaTypeId<QJSValue>()) {
- if (QV4::Value *v4Value = QJSValuePrivate::valueForData(reinterpret_cast<QJSValue *>(a[ii + 1]), &jsCall->args[ii]))
- jsCall->args[ii] = *v4Value;
- else
- jsCall->args[ii] = QV4::Encode::undefined();
+ jsCall->args[ii] = QJSValuePrivate::asReturnedValue(reinterpret_cast<QJSValue *>(a[ii + 1]));
} else if (type == QMetaType::QVariant) {
jsCall->args[ii] = scope.engine->fromVariant(*((QVariant *)a[ii + 1]));
} else if (type == QMetaType::Int) {
diff --git a/src/qml/qml/qqmlengine.cpp b/src/qml/qml/qqmlengine.cpp
index c2f8459fb1..0d9326b9a9 100644
--- a/src/qml/qml/qqmlengine.cpp
+++ b/src/qml/qml/qqmlengine.cpp
@@ -2518,7 +2518,7 @@ QJSValue QQmlEnginePrivate::singletonInstance<QJSValue>(const QQmlType &type)
// should behave identically to QML singleton types.
q->setContextForObject(o, new QQmlContext(q->rootContext(), q));
}
- singletonInstances.insert(type, value);
+ singletonInstances.convertAndInsert(v4engine(), type, &value);
} else if (siinfo->qobjectCallback) {
QObject *o = siinfo->qobjectCallback(q, q);
@@ -2536,12 +2536,12 @@ QJSValue QQmlEnginePrivate::singletonInstance<QJSValue>(const QQmlType &type)
// should behave identically to QML singleton types.
q->setContextForObject(o, new QQmlContext(q->rootContext(), q));
value = q->newQObject(o);
- singletonInstances.insert(type, value);
+ singletonInstances.convertAndInsert(v4engine(), type, &value);
} else if (!siinfo->url.isEmpty()) {
QQmlComponent component(q, siinfo->url, QQmlComponent::PreferSynchronous);
QObject *o = component.beginCreate(q->rootContext());
value = q->newQObject(o);
- singletonInstances.insert(type, value);
+ singletonInstances.convertAndInsert(v4engine(), type, &value);
component.completeCreate();
}
diff --git a/src/qml/qml/qqmlengine_p.h b/src/qml/qml/qqmlengine_p.h
index fe42d4e347..23c69651ed 100644
--- a/src/qml/qml/qqmlengine_p.h
+++ b/src/qml/qml/qqmlengine_p.h
@@ -67,6 +67,7 @@
#include <private/qrecyclepool_p.h>
#include <private/qfieldlist_p.h>
#include <private/qv4engine_p.h>
+#include <private/qjsvalue_p.h>
#include <QtCore/qlist.h>
#include <QtCore/qpair.h>
@@ -285,7 +286,20 @@ public:
}
private:
- QHash<QQmlType, QJSValue> singletonInstances;
+ class SingletonInstances : private QHash<QQmlType, QJSValue>
+ {
+ public:
+ void convertAndInsert(QV4::ExecutionEngine *engine, const QQmlType &type, QJSValue *value)
+ {
+ QJSValuePrivate::manageStringOnV4Heap(engine, value);
+ insert(type, *value);
+ }
+
+ using QHash<QQmlType, QJSValue>::value;
+ using QHash<QQmlType, QJSValue>::take;
+ };
+
+ SingletonInstances singletonInstances;
QHash<int, QQmlGadgetPtrWrapper *> cachedValueTypeInstances;
// These members must be protected by a QQmlEnginePrivate::Locker as they are required by
diff --git a/src/qml/qml/qqmlobjectcreator.cpp b/src/qml/qml/qqmlobjectcreator.cpp
index 040fa16af8..e0187eb75a 100644
--- a/src/qml/qml/qqmlobjectcreator.cpp
+++ b/src/qml/qml/qqmlobjectcreator.cpp
@@ -1068,7 +1068,7 @@ bool QQmlObjectCreator::setPropertyBinding(const QQmlPropertyData *bindingProper
_vmeMetaObject->setVMEProperty(bindingProperty->coreIndex(), wrappedObject);
} else {
QJSValue value;
- QJSValuePrivate::setValue(&value, v4, wrappedObject);
+ QJSValuePrivate::setValue(&value, wrappedObject);
argv[0] = &value;
QMetaObject::metacall(_qobject, QMetaObject::WriteProperty, bindingProperty->coreIndex(), argv);
}
diff --git a/src/qml/qml/qqmltypewrapper.cpp b/src/qml/qml/qqmltypewrapper.cpp
index 7bcc5e9900..c787d4092e 100644
--- a/src/qml/qml/qqmltypewrapper.cpp
+++ b/src/qml/qml/qqmltypewrapper.cpp
@@ -233,7 +233,7 @@ ReturnedValue QQmlTypeWrapper::virtualGet(const Managed *m, PropertyKey id, cons
QJSValue scriptSingleton = e->singletonInstance<QJSValue>(type);
if (!scriptSingleton.isUndefined()) {
// NOTE: if used in a binding, changes will not trigger re-evaluation since non-NOTIFYable.
- QV4::ScopedObject o(scope, QJSValuePrivate::convertedToValue(v4, scriptSingleton));
+ QV4::ScopedObject o(scope, QJSValuePrivate::asReturnedValue(&scriptSingleton));
if (!!o)
return o->get(name);
}
@@ -349,7 +349,7 @@ bool QQmlTypeWrapper::virtualPut(Managed *m, PropertyKey id, const Value &value,
} else {
QJSValue scriptSingleton = e->singletonInstance<QJSValue>(type);
if (!scriptSingleton.isUndefined()) {
- QV4::ScopedObject apiprivate(scope, QJSValuePrivate::convertedToValue(scope.engine, scriptSingleton));
+ QV4::ScopedObject apiprivate(scope, QJSValuePrivate::asReturnedValue(&scriptSingleton));
if (!apiprivate) {
QString error = QLatin1String("Cannot assign to read-only property \"") + name->toQString() + QLatin1Char('\"');
scope.engine->throwError(error);
diff --git a/src/qmlmodels/qqmldelegatemodel.cpp b/src/qmlmodels/qqmldelegatemodel.cpp
index 095b66b379..08c91d172e 100644
--- a/src/qmlmodels/qqmldelegatemodel.cpp
+++ b/src/qmlmodels/qqmldelegatemodel.cpp
@@ -48,6 +48,7 @@
#include <private/qqmlchangeset_p.h>
#include <private/qqmlengine_p.h>
#include <private/qqmlcomponent_p.h>
+#include <private/qjsvalue_p.h>
#include <private/qv4value_p.h>
#include <private/qv4functionobject_p.h>
@@ -2656,8 +2657,10 @@ void QQmlDelegateModelGroupPrivate::emitChanges(QV4::ExecutionEngine *v4)
{
Q_Q(QQmlDelegateModelGroup);
if (isChangedConnected() && !changeSet.isEmpty()) {
- emit q->changed(QJSValue(v4, engineData(v4)->array(v4, changeSet.removes())),
- QJSValue(v4, engineData(v4)->array(v4, changeSet.inserts())));
+ emit q->changed(QJSValuePrivate::fromReturnedValue(
+ engineData(v4)->array(v4, changeSet.removes())),
+ QJSValuePrivate::fromReturnedValue(
+ engineData(v4)->array(v4, changeSet.inserts())));
}
if (changeSet.difference() != 0)
emit q->countChanged();
@@ -2874,7 +2877,7 @@ QJSValue QQmlDelegateModelGroup::get(int index)
QV4::ScopedObject p(scope, model->m_cacheMetaType->modelItemProto.value());
o->setPrototypeOf(p);
- return QJSValue(v4, o->asReturnedValue());
+ return QJSValuePrivate::fromReturnedValue(o->asReturnedValue());
}
bool QQmlDelegateModelGroupPrivate::parseIndex(const QV4::Value &value, int *index, Compositor::Group *group) const
diff --git a/src/qmlmodels/qqmllistmodel.cpp b/src/qmlmodels/qqmllistmodel.cpp
index e58fc19178..0d45d03fa6 100644
--- a/src/qmlmodels/qqmllistmodel.cpp
+++ b/src/qmlmodels/qqmllistmodel.cpp
@@ -589,7 +589,7 @@ void ListModel::set(int elementIndex, QV4::Object *object, QVector<int> *roles)
const ListLayout::Role &r = m_layout->getRoleOrCreate(propertyName, ListLayout::Role::Function);
QV4::ScopedFunctionObject func(scope, f);
QJSValue jsv;
- QJSValuePrivate::setValue(&jsv, v4, func);
+ QJSValuePrivate::setValue(&jsv, func);
roleIndex = e->setFunctionProperty(r, jsv);
} else if (QV4::Object *o = propertyValue->as<QV4::Object>()) {
if (QV4::QObjectWrapper *wrapper = o->as<QV4::QObjectWrapper>()) {
@@ -1434,7 +1434,7 @@ int ListElement::setJsProperty(const ListLayout::Role &role, const QV4::Value &d
} else if (d.as<QV4::FunctionObject>()) {
QV4::ScopedFunctionObject f(scope, d);
QJSValue jsv;
- QJSValuePrivate::setValue(&jsv, eng, f);
+ QJSValuePrivate::setValue(&jsv, f);
roleIndex = setFunctionProperty(role, jsv);
} else if (d.isObject()) {
QV4::ScopedObject o(scope, d);
@@ -1638,7 +1638,8 @@ PropertyKey ModelObjectOwnPropertyKeyIterator::next(const Object *o, Property *p
auto size = recursiveListModel->count();
auto array = ScopedArrayObject{scope, v4->newArrayObject(size)};
for (auto i = 0; i < size; i++) {
- array->arrayPut(i, QJSValuePrivate::convertedToValue(v4, recursiveListModel->get(i)));
+ array->arrayPut(i, QJSValuePrivate::convertToReturnedValue(
+ v4, recursiveListModel->get(i)));
}
pd->value = array;
} else {
@@ -2570,7 +2571,7 @@ QJSValue QQmlListModel::get(int index) const
}
}
- return QJSValue(engine(), result->asReturnedValue());
+ return QJSValuePrivate::fromReturnedValue(result->asReturnedValue());
}
/*!
@@ -2592,7 +2593,7 @@ QJSValue QQmlListModel::get(int index) const
void QQmlListModel::set(int index, const QJSValue &value)
{
QV4::Scope scope(engine());
- QV4::ScopedObject object(scope, QJSValuePrivate::getValue(&value));
+ QV4::ScopedObject object(scope, QJSValuePrivate::asReturnedValue(&value));
if (!object) {
qmlWarning(this) << tr("set: value is not an object");
@@ -2791,7 +2792,7 @@ bool QQmlListModelParser::applyProperty(
if (v4->hasException)
v4->catchException();
else
- QJSValuePrivate::setValue(&v, v4, result->asReturnedValue());
+ QJSValuePrivate::setValue(&v, result->asReturnedValue());
value.setValue<QJSValue>(v);
} else {
QByteArray script = scriptStr.toUtf8();
diff --git a/src/qmlworkerscript/qquickworkerscript.cpp b/src/qmlworkerscript/qquickworkerscript.cpp
index 20294d7ba7..705c6015a2 100644
--- a/src/qmlworkerscript/qquickworkerscript.cpp
+++ b/src/qmlworkerscript/qquickworkerscript.cpp
@@ -41,6 +41,7 @@
#include "qquickworkerscript_p.h"
#include <private/qqmlengine_p.h>
#include <private/qqmlexpression_p.h>
+#include <private/qjsvalue_p.h>
#include <QtCore/qcoreevent.h>
#include <QtCore/qcoreapplication.h>
@@ -644,7 +645,8 @@ bool QQuickWorkerScript::event(QEvent *event)
if (QQmlEngine *engine = qmlEngine(this)) {
QV4::ExecutionEngine *v4 = engine->handle();
WorkerDataEvent *workerEvent = static_cast<WorkerDataEvent *>(event);
- emit message(QJSValue(v4, QV4::Serialize::deserialize(workerEvent->data(), v4)));
+ emit message(QJSValuePrivate::fromReturnedValue(
+ QV4::Serialize::deserialize(workerEvent->data(), v4)));
}
return true;
} else if (event->type() == (QEvent::Type)WorkerErrorEvent::WorkerError) {
diff --git a/src/quick/items/context2d/qquickcanvasitem.cpp b/src/quick/items/context2d/qquickcanvasitem.cpp
index bfee190baf..a15533418c 100644
--- a/src/quick/items/context2d/qquickcanvasitem.cpp
+++ b/src/quick/items/context2d/qquickcanvasitem.cpp
@@ -59,6 +59,7 @@
#include <private/qv4scopedvalue_p.h>
#include <private/qv4jscall_p.h>
#include <private/qv4qobjectwrapper_p.h>
+#include <private/qjsvalue_p.h>
QT_BEGIN_NAMESPACE
@@ -381,7 +382,7 @@ void QQuickCanvasItem::setContextType(const QString &contextType)
QJSValue QQuickCanvasItem::context() const
{
Q_D(const QQuickCanvasItem);
- return d->context ? QJSValue(d->context->v4Engine(), d->context->v4value()) : QJSValue();
+ return d->context ? QJSValuePrivate::fromReturnedValue(d->context->v4value()) : QJSValue();
}
/*!