aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorAndrew den Exter <andrew.den-exter@nokia.com>2012-05-11 17:37:07 +1000
committerQt by Nokia <qt-info@nokia.com>2012-05-24 05:52:32 +0200
commit4709f30b26042427b225dd164648e3f5907c9d33 (patch)
tree3edac8d14d3fb77406ef93aa2c34c42131109625 /src
parent2542778d4837143a61dfcf143c32683acc8b998a (diff)
Enable binding to properties of type QJSValue.
This allows javascript objects of all types to be bound to properties declared in c++. Compared to a QVariant the primary benefit this offers is a type which functions and objects with functions can be bound to. Change-Id: Idb3313e7ff1d616ab12d44f616083c8296201f3a Reviewed-by: Kent Hansen <kent.hansen@nokia.com>
Diffstat (limited to 'src')
-rw-r--r--src/qml/qml/qqmlcompiler.cpp29
-rw-r--r--src/qml/qml/qqmlinstruction_p.h4
-rw-r--r--src/qml/qml/qqmlproperty.cpp10
-rw-r--r--src/qml/qml/qqmlvme.cpp5
-rw-r--r--src/qml/qml/v4/qv4bindings.cpp191
-rw-r--r--src/qml/qml/v4/qv4compiler.cpp22
-rw-r--r--src/qml/qml/v4/qv4instruction.cpp30
-rw-r--r--src/qml/qml/v4/qv4instruction_p.h10
-rw-r--r--src/qml/qml/v4/qv4ir.cpp1
-rw-r--r--src/qml/qml/v4/qv4ir_p.h1
-rw-r--r--src/qml/qml/v4/qv4irbuilder.cpp4
-rw-r--r--src/qml/qml/v4/qv4program_p.h3
-rw-r--r--src/qml/qml/v8/qv8engine.cpp3
-rw-r--r--src/qml/qml/v8/qv8qobjectwrapper.cpp10
14 files changed, 319 insertions, 4 deletions
diff --git a/src/qml/qml/qqmlcompiler.cpp b/src/qml/qml/qqmlcompiler.cpp
index c3d134f6a8..d568cc463f 100644
--- a/src/qml/qml/qqmlcompiler.cpp
+++ b/src/qml/qml/qqmlcompiler.cpp
@@ -77,6 +77,7 @@ Q_DECLARE_METATYPE(QList<qreal>)
Q_DECLARE_METATYPE(QList<bool>)
Q_DECLARE_METATYPE(QList<QString>)
Q_DECLARE_METATYPE(QList<QUrl>)
+Q_DECLARE_METATYPE(QJSValue)
QT_BEGIN_NAMESPACE
@@ -395,6 +396,8 @@ bool QQmlCompiler::testLiteralAssignment(QQmlScript::Property *prop,
COMPILE_EXCEPTION(v, tr("Invalid property assignment: url or array of urls expected"));
}
break;
+ } else if (type == qMetaTypeId<QJSValue>()) {
+ break;
}
// otherwise, check for existence of string converter to custom type
@@ -724,6 +727,32 @@ void QQmlCompiler::genLiteralAssignment(QQmlScript::Property *prop,
instr.value = output->indexForString(v->value.asString());
output->addInstruction(instr);
break;
+ } else if (type == qMetaTypeId<QJSValue>()) {
+ if (v->value.isBoolean()) {
+ Instruction::StoreJSValueBool instr;
+ instr.propertyIndex = prop->index;
+ instr.value = v->value.asBoolean();
+ output->addInstruction(instr);
+ } else if (v->value.isNumber()) {
+ double n = v->value.asNumber();
+ if (double(int(n)) == n) {
+ Instruction::StoreJSValueInteger instr;
+ instr.propertyIndex = prop->index;
+ instr.value = int(n);
+ output->addInstruction(instr);
+ } else {
+ Instruction::StoreJSValueDouble instr;
+ instr.propertyIndex = prop->index;
+ instr.value = n;
+ output->addInstruction(instr);
+ }
+ } else {
+ Instruction::StoreJSValueString instr;
+ instr.propertyIndex = prop->index;
+ instr.value = output->indexForString(v->value.asString());
+ output->addInstruction(instr);
+ }
+ break;
}
// otherwise, generate custom type literal assignment
diff --git a/src/qml/qml/qqmlinstruction_p.h b/src/qml/qml/qqmlinstruction_p.h
index 533734b622..04f419d9d5 100644
--- a/src/qml/qml/qqmlinstruction_p.h
+++ b/src/qml/qml/qqmlinstruction_p.h
@@ -79,6 +79,10 @@ QT_BEGIN_NAMESPACE
F(StoreVarDouble, storeDouble) \
F(StoreVarBool, storeBool) \
F(StoreString, storeString) \
+ F(StoreJSValueString, storeString) \
+ F(StoreJSValueInteger, storeInteger) \
+ F(StoreJSValueDouble, storeDouble) \
+ F(StoreJSValueBool, storeBool) \
F(StoreStringList, storeString) \
F(StoreStringQList, storeString) \
F(StoreTrString, storeTrString) \
diff --git a/src/qml/qml/qqmlproperty.cpp b/src/qml/qml/qqmlproperty.cpp
index 761b75acf4..087fbaa9bf 100644
--- a/src/qml/qml/qqmlproperty.cpp
+++ b/src/qml/qml/qqmlproperty.cpp
@@ -62,6 +62,7 @@
#include <math.h>
+Q_DECLARE_METATYPE(QJSValue)
Q_DECLARE_METATYPE(QList<int>)
Q_DECLARE_METATYPE(QList<qreal>)
Q_DECLARE_METATYPE(QList<bool>)
@@ -1489,7 +1490,7 @@ bool QQmlPropertyPrivate::writeBinding(QObject *object,
value = QVariant::fromValue((QObject *)0);
} else if (core.propType == qMetaTypeId<QList<QUrl> >()) {
value = resolvedUrlSequence(v8engine->toVariant(result, qMetaTypeId<QList<QUrl> >()), context);
- } else if (!isVmeProperty) {
+ } else if (!isVmeProperty && type != qMetaTypeId<QJSValue>()) {
value = v8engine->toVariant(result, type);
}
@@ -1511,6 +1512,13 @@ bool QQmlPropertyPrivate::writeBinding(QObject *object,
QMetaObject::metacall(object, QMetaObject::ResetProperty, core.coreIndex, args);
} else if (isUndefined && type == qMetaTypeId<QVariant>()) {
writeValueProperty(object, engine, core, QVariant(), context, flags);
+ } else if (type == qMetaTypeId<QJSValue>()) {
+ if (!result.IsEmpty() && result->IsFunction()
+ && !result->ToObject()->GetHiddenValue(v8engine->bindingFlagKey()).IsEmpty()) {
+ expression->delayedError()->error.setDescription(QLatin1String("Invalid use of Qt.binding() in a binding declaration."));
+ return false;
+ }
+ writeValueProperty(object, engine, core, QVariant::fromValue(v8engine->scriptValueFromInternal(result)), context, flags);
} else if (isUndefined) {
expression->delayedError()->error.setDescription(QLatin1String("Unable to assign [undefined] to ") + QLatin1String(QMetaType::typeName(type)));
return false;
diff --git a/src/qml/qml/qqmlvme.cpp b/src/qml/qml/qqmlvme.cpp
index b86e3beaae..1665342ffd 100644
--- a/src/qml/qml/qqmlvme.cpp
+++ b/src/qml/qml/qqmlvme.cpp
@@ -426,6 +426,11 @@ QObject *QQmlVME::run(QList<QQmlError> *errors,
QML_STORE_VAR(StoreVarDouble, v8::Number::New(instr.value));
QML_STORE_VAR(StoreVarBool, v8::Boolean::New(instr.value));
+ // Store a literal value in a QJSValue property.
+ QML_STORE_VALUE(StoreJSValueString, QJSValue, QJSValue(PRIMITIVES.at(instr.value)));
+ QML_STORE_VALUE(StoreJSValueInteger, QJSValue, QJSValue(instr.value));
+ QML_STORE_VALUE(StoreJSValueDouble, QJSValue, QJSValue(instr.value));
+ QML_STORE_VALUE(StoreJSValueBool, QJSValue, QJSValue(instr.value));
QML_BEGIN_INSTR(Init)
// Ensure that the compiled data has been initialized
diff --git a/src/qml/qml/v4/qv4bindings.cpp b/src/qml/qml/v4/qv4bindings.cpp
index d4665ac9be..3c03edbca6 100644
--- a/src/qml/qml/v4/qv4bindings.cpp
+++ b/src/qml/qml/v4/qv4bindings.cpp
@@ -51,6 +51,8 @@
#include <private/qv8_p.h>
#include <private/qjsconverter_p.h>
#include <private/qjsconverter_impl_p.h>
+#include <private/qjsvalue_impl_p.h>
+#include <private/qv8engine_impl_p.h>
#include <private/qqmlaccessors_p.h>
#include <private/qqmlprofilerservice_p.h>
@@ -65,6 +67,8 @@
#include <QtCore/qmath.h>
#include <math.h> // ::fmod
+Q_DECLARE_METATYPE(QJSValue)
+
QT_BEGIN_NAMESPACE
using namespace QQmlJS;
@@ -101,11 +105,13 @@ struct Register {
inline QString *getstringptr() { return reinterpret_cast<QString *>(typeDataPtr()); }
inline QUrl *geturlptr() { return reinterpret_cast<QUrl *>(typeDataPtr()); }
inline v8::Handle<v8::Value> *gethandleptr() { return reinterpret_cast<v8::Handle<v8::Value> *>(typeDataPtr()); }
+ inline QJSValue *getjsvalueptr() { return reinterpret_cast<QJSValue *>(typeDataPtr()); }
inline const QVariant *getvariantptr() const { return reinterpret_cast<const QVariant *>(typeDataPtr()); }
inline const QString *getstringptr() const { return reinterpret_cast<const QString *>(typeDataPtr()); }
inline const QUrl *geturlptr() const { return reinterpret_cast<const QUrl *>(typeDataPtr()); }
inline const v8::Handle<v8::Value> *gethandleptr() const { return reinterpret_cast<const v8::Handle<v8::Value> *>(typeDataPtr()); }
+ inline const QJSValue *getjsvalueptr() const { return reinterpret_cast<const QJSValue *>(typeDataPtr()); }
size_t dataSize() { return sizeof(data); }
inline void *typeDataPtr() { return (void *)&data; }
@@ -134,6 +140,7 @@ struct Register {
inline void cleanupColor();
inline void cleanupVariant();
inline void cleanupHandle();
+ inline void cleanupJSValue();
inline void copy(const Register &other);
inline void init(Type type);
@@ -180,6 +187,8 @@ void Register::cleanup()
getvariantptr()->~QVariant();
} else if (dataType == qMetaTypeId<v8::Handle<v8::Value> >()) {
destroyPointee(gethandleptr());
+ } else if (dataType == qMetaTypeId<QJSValue>()) {
+ getjsvalueptr()->~QJSValue();
}
}
setUndefined();
@@ -215,6 +224,12 @@ void Register::cleanupHandle()
setUndefined();
}
+void Register::cleanupJSValue()
+{
+ getjsvalueptr()->~QJSValue();
+ setUndefined();
+}
+
void Register::copy(const Register &other)
{
*this = other;
@@ -229,6 +244,8 @@ void Register::copy(const Register &other)
new (getvariantptr()) QVariant(*other.getvariantptr());
else if (other.dataType == qMetaTypeId<v8::Handle<v8::Value> >())
copyConstructPointee(gethandleptr(), other.gethandleptr());
+ else if (other.dataType == qMetaTypeId<QJSValue>())
+ new (getjsvalueptr()) QJSValue(*other.getjsvalueptr());
}
}
@@ -246,6 +263,8 @@ void Register::init(Type type)
new (getvariantptr()) QVariant();
else if (dataType == qMetaTypeId<v8::Handle<v8::Value> >())
defaultConstructPointee(gethandleptr());
+ else if (dataType == qMetaTypeId<QJSValue>())
+ new (getjsvalueptr()) QJSValue();
}
}
@@ -716,6 +735,11 @@ inline quint32 QV4Bindings::toUint32(double n)
MARK_REGISTER(reg); \
}
+#define JSVALUE_REGISTER(reg) { \
+ registers[(reg)].settype(QJSValueType); \
+ MARK_REGISTER(reg); \
+}
+
#ifdef QML_THREADED_INTERPRETER
void **QV4Bindings::getDecodeInstrTable()
{
@@ -935,6 +959,19 @@ void QV4Bindings::run(int instrIndex, quint32 &executedBlocks,
}
QML_V4_END_INSTR(ConvertBoolToInt, unaryop)
+ QML_V4_BEGIN_INSTR(ConvertBoolToJSValue, unaryop)
+ {
+ const Register &src = registers[instr->unaryop.src];
+ Register &output = registers[instr->unaryop.output];
+ if (src.isUndefined()) {
+ output.setUndefined();
+ } else {
+ new (output.getjsvalueptr()) QJSValue(src.getbool());
+ JSVALUE_REGISTER(instr->unaryop.output);
+ }
+ }
+ QML_V4_END_INSTR(ConvertBoolToJSValue, unaryop)
+
QML_V4_BEGIN_INSTR(ConvertBoolToNumber, unaryop)
{
const Register &src = registers[instr->unaryop.src];
@@ -992,6 +1029,19 @@ void QV4Bindings::run(int instrIndex, quint32 &executedBlocks,
}
QML_V4_END_INSTR(ConvertIntToBool, unaryop)
+ QML_V4_BEGIN_INSTR(ConvertIntToJSValue, unaryop)
+ {
+ const Register &src = registers[instr->unaryop.src];
+ Register &output = registers[instr->unaryop.output];
+ if (src.isUndefined()) {
+ output.setUndefined();
+ } else {
+ new (output.getjsvalueptr()) QJSValue(src.getint());
+ JSVALUE_REGISTER(instr->unaryop.output);
+ }
+ }
+ QML_V4_END_INSTR(ConvertIntToJSValue, unaryop)
+
QML_V4_BEGIN_INSTR(ConvertIntToNumber, unaryop)
{
const Register &src = registers[instr->unaryop.src];
@@ -1040,6 +1090,30 @@ void QV4Bindings::run(int instrIndex, quint32 &executedBlocks,
}
QML_V4_END_INSTR(ConvertIntToVar, unaryop)
+ QML_V4_BEGIN_INSTR(ConvertJSValueToVar, unaryop)
+ {
+ const Register &src = registers[instr->unaryop.src];
+ Register &output = registers[instr->unaryop.output];
+ if (src.isUndefined()) {
+ output.setUndefined();
+ } else {
+ QJSValue tmp(*src.getjsvalueptr());
+ if (instr->unaryop.src == instr->unaryop.output) {
+ output.cleanupJSValue();
+ MARK_CLEAN_REGISTER(instr->unaryop.output);
+ }
+ if (tmp.isUndefined()) {
+ output.setUndefined();
+ } else {
+ QV8Engine *v8engine = QQmlEnginePrivate::get(context->engine)->v8engine();
+ new (output.gethandleptr()) v8::Handle<v8::Value>(
+ QJSValuePrivate::get(tmp)->asV8Value(v8engine));
+ V8HANDLE_REGISTER(instr->unaryop.output);
+ }
+ }
+ }
+ QML_V4_END_INSTR(ConvertJSValueToVar, unaryop)
+
QML_V4_BEGIN_INSTR(ConvertNumberToBool, unaryop)
{
const Register &src = registers[instr->unaryop.src];
@@ -1058,6 +1132,19 @@ void QV4Bindings::run(int instrIndex, quint32 &executedBlocks,
}
QML_V4_END_INSTR(ConvertNumberToInt, unaryop)
+ QML_V4_BEGIN_INSTR(ConvertNumberToJSValue, unaryop)
+ {
+ const Register &src = registers[instr->unaryop.src];
+ Register &output = registers[instr->unaryop.output];
+ if (src.isUndefined()) {
+ output.setUndefined();
+ } else {
+ new (output.getjsvalueptr()) QJSValue(src.getnumber());
+ JSVALUE_REGISTER(instr->unaryop.output);
+ }
+ }
+ QML_V4_END_INSTR(ConvertNumberToJSValue, unaryop)
+
QML_V4_BEGIN_INSTR(ConvertNumberToString, unaryop)
{
const Register &src = registers[instr->unaryop.src];
@@ -1138,6 +1225,24 @@ void QV4Bindings::run(int instrIndex, quint32 &executedBlocks,
}
QML_V4_END_INSTR(ConvertStringToInt, unaryop)
+ QML_V4_BEGIN_INSTR(ConvertStringToJSValue, unaryop)
+ {
+ const Register &src = registers[instr->unaryop.src];
+ Register &output = registers[instr->unaryop.output];
+ if (src.isUndefined()) {
+ output.setUndefined();
+ } else {
+ QString tmp(*src.getstringptr());
+ if (instr->unaryop.src == instr->unaryop.output) {
+ output.cleanupString();
+ MARK_CLEAN_REGISTER(instr->unaryop.output);
+ }
+ new (output.getjsvalueptr()) QJSValue(tmp);
+ JSVALUE_REGISTER(instr->unaryop.output);
+ }
+ }
+ QML_V4_END_INSTR(ConvertStringToJSValue, unaryop)
+
QML_V4_BEGIN_INSTR(ConvertStringToNumber, unaryop)
{
const Register &src = registers[instr->unaryop.src];
@@ -1253,6 +1358,24 @@ void QV4Bindings::run(int instrIndex, quint32 &executedBlocks,
}
QML_V4_END_INSTR(ConvertUrlToBool, unaryop)
+ QML_V4_BEGIN_INSTR(ConvertUrlToJSValue, unaryop)
+ {
+ const Register &src = registers[instr->unaryop.src];
+ Register &output = registers[instr->unaryop.output];
+ if (src.isUndefined()) {
+ output.setUndefined();
+ } else {
+ const QUrl tmp(*src.geturlptr());
+ if (instr->unaryop.src == instr->unaryop.output) {
+ output.cleanupUrl();
+ MARK_CLEAN_REGISTER(instr->unaryop.output);
+ }
+ new (output.getjsvalueptr()) QJSValue(tmp.toString());
+ JSVALUE_REGISTER(instr->unaryop.output);
+ }
+ }
+ QML_V4_END_INSTR(ConvertUrlToJSValue, unaryop)
+
QML_V4_BEGIN_INSTR(ConvertUrlToString, unaryop)
{
const Register &src = registers[instr->unaryop.src];
@@ -1324,6 +1447,31 @@ void QV4Bindings::run(int instrIndex, quint32 &executedBlocks,
}
QML_V4_END_INSTR(ConvertColorToBool, unaryop)
+ QML_V4_BEGIN_INSTR(ConvertColorToJSValue, unaryop)
+ {
+ const Register &src = registers[instr->unaryop.src];
+ Register &output = registers[instr->unaryop.output];
+ if (src.isUndefined()) {
+ output.setUndefined();
+ } else {
+ const QVariant tmp(QMetaType::QColor, src.typeDataPtr());
+ if (instr->unaryop.src == instr->unaryop.output) {
+ output.cleanupColor();
+ MARK_CLEAN_REGISTER(instr->unaryop.output);
+ }
+
+ QQmlEnginePrivate *ep = QQmlEnginePrivate::get(context->engine);
+ QV8Engine *v8engine = ep->v8engine();
+ QQmlValueType *vt = ep->valueTypes[QMetaType::QColor];
+ v8::HandleScope handle_scope;
+ v8::Context::Scope scope(v8engine->context());
+ new (output.getjsvalueptr()) QJSValue(v8engine->scriptValueFromInternal(
+ v8engine->valueTypeWrapper()->newValueType(tmp, vt)));
+ JSVALUE_REGISTER(instr->unaryop.output);
+ }
+ }
+ QML_V4_END_INSTR(ConvertColorToJSValue, unaryop)
+
QML_V4_BEGIN_INSTR(ConvertColorToString, unaryop)
{
const Register &src = registers[instr->unaryop.src];
@@ -1391,6 +1539,22 @@ void QV4Bindings::run(int instrIndex, quint32 &executedBlocks,
}
QML_V4_END_INSTR(ConvertObjectToBool, unaryop)
+ QML_V4_BEGIN_INSTR(ConvertObjectToJSValue, unaryop)
+ {
+ const Register &src = registers[instr->unaryop.src];
+ Register &output = registers[instr->unaryop.output];
+ if (src.isUndefined()) {
+ output.setUndefined();
+ } else {
+ QQmlEnginePrivate *ep = QQmlEnginePrivate::get(context->engine);
+ v8::HandleScope handle_scope;
+ v8::Context::Scope scope(ep->v8engine()->context());
+ new (output.getjsvalueptr()) QJSValue(context->engine->newQObject(src.getQObject()));
+ JSVALUE_REGISTER(instr->unaryop.output);
+ }
+ }
+ QML_V4_END_INSTR(ConvertObjectToJSValue, unaryop)
+
QML_V4_BEGIN_INSTR(ConvertObjectToVariant, unaryop)
{
const Register &src = registers[instr->unaryop.src];
@@ -1420,6 +1584,33 @@ void QV4Bindings::run(int instrIndex, quint32 &executedBlocks,
}
QML_V4_END_INSTR(ConvertObjectToVar, unaryop)
+ QML_V4_BEGIN_INSTR(ConvertVarToJSValue, unaryop)
+ {
+ const Register &src = registers[instr->unaryop.src];
+ Register &output = registers[instr->unaryop.output];
+ if (src.isUndefined()) {
+ output.setUndefined();
+ } else {
+ v8::Handle<v8::Value> tmp(*src.gethandleptr());
+ if (instr->unaryop.src == instr->unaryop.output) {
+ output.cleanupHandle();
+ MARK_CLEAN_REGISTER(instr->unaryop.output);
+ }
+ QV8Engine *v8engine = QQmlEnginePrivate::get(context->engine)->v8engine();
+ new (output.getjsvalueptr()) QJSValue(v8engine->scriptValueFromInternal(tmp));
+ JSVALUE_REGISTER(instr->unaryop.output);
+ }
+ }
+ QML_V4_END_INSTR(ConvertVarToJSValue, unaryop)
+
+ QML_V4_BEGIN_INSTR(ConvertNullToJSValue, unaryop)
+ {
+ Register &output = registers[instr->unaryop.output];
+ new (output.getjsvalueptr()) QJSValue(QJSValue::NullValue);
+ JSVALUE_REGISTER(instr->unaryop.output);
+ }
+ QML_V4_END_INSTR(ConvertNullToJSValue, unaryop)
+
QML_V4_BEGIN_INSTR(ConvertNullToObject, unaryop)
{
Register &output = registers[instr->unaryop.output];
diff --git a/src/qml/qml/v4/qv4compiler.cpp b/src/qml/qml/v4/qv4compiler.cpp
index 783e147ba0..1c163364a3 100644
--- a/src/qml/qml/v4/qv4compiler.cpp
+++ b/src/qml/qml/v4/qv4compiler.cpp
@@ -50,6 +50,8 @@
#include <private/qqmlaccessors_p.h>
#include <private/qqmljsengine_p.h>
+Q_DECLARE_METATYPE(QJSValue)
+
QT_BEGIN_NAMESPACE
DEFINE_BOOL_CONFIG_OPTION(bindingsDump, QML_BINDINGS_DUMP)
@@ -971,6 +973,7 @@ void QV4CompilerPrivate::visitMove(IR::Move *s)
case IR::StringType:
case IR::VariantType:
case IR::VarType:
+ case IR::JSValueType:
// nothing to do. V4 will generate optimized
// url-to-xxx conversions.
break;
@@ -1098,9 +1101,25 @@ void QV4CompilerPrivate::visitMove(IR::Move *s)
case IR::StringType: opcode = V4Instr::ConvertStringToVar; break;
case IR::ObjectType: opcode = V4Instr::ConvertObjectToVar; break;
case IR::NullType: opcode = V4Instr::ConvertNullToVar; break;
+ case IR::JSValueType: opcode = V4Instr::ConvertJSValueToVar; break;
default: break;
} // switch
}
+ } else if (targetTy == IR::JSValueType) {
+ if (s->isMoveForReturn) {
+ switch (sourceTy) {
+ case IR::BoolType: opcode = V4Instr::ConvertBoolToJSValue; break;
+ case IR::IntType: opcode = V4Instr::ConvertIntToJSValue; break;
+ case IR::NumberType: opcode = V4Instr::ConvertNumberToJSValue; break;
+ case IR::UrlType: opcode = V4Instr::ConvertUrlToJSValue; break;
+ case IR::ColorType: opcode = V4Instr::ConvertColorToJSValue; break;
+ case IR::StringType: opcode = V4Instr::ConvertStringToJSValue; break;
+ case IR::ObjectType: opcode = V4Instr::ConvertObjectToJSValue; break;
+ case IR::VarType: opcode = V4Instr::ConvertVarToJSValue; break;
+ case IR::NullType: opcode = V4Instr::ConvertNullToJSValue; break;
+ default: break;
+ }
+ }
}
if (opcode != V4Instr::Noop) {
V4Instr conv;
@@ -1180,6 +1199,9 @@ void QV4CompilerPrivate::visitRet(IR::Ret *s)
case IR::VarType:
test.regType = qMetaTypeId<v8::Handle<v8::Value> >();
break;
+ case IR::JSValueType:
+ test.regType = qMetaTypeId<QJSValue>();
+ break;
case IR::BoolType:
test.regType = QMetaType::Bool;
break;
diff --git a/src/qml/qml/v4/qv4instruction.cpp b/src/qml/qml/v4/qv4instruction.cpp
index fccb0f7b98..1fbdf3e325 100644
--- a/src/qml/qml/v4/qv4instruction.cpp
+++ b/src/qml/qml/v4/qv4instruction.cpp
@@ -138,6 +138,9 @@ void Bytecode::dump(const V4Instr *i, int address) const
case V4Instr::ConvertBoolToInt:
INSTR_DUMP << '\t' << "ConvertBoolToInt" << '\t' << "Input_Reg(" << i->unaryop.src << ") -> Output_Reg(" << i->unaryop.output << ')';
break;
+ case V4Instr::ConvertBoolToJSValue:
+ INSTR_DUMP << '\t' << "ConvertBoolToJSValue" << '\t' << "Input_Reg(" << i->unaryop.src << ") -> Output_Reg(" << i->unaryop.output << ')';
+ break;
case V4Instr::ConvertBoolToNumber:
INSTR_DUMP << '\t' << "ConvertBoolToNumber" << '\t' << "Input_Reg(" << i->unaryop.src << ") -> Output_Reg(" << i->unaryop.output << ')';
break;
@@ -153,6 +156,9 @@ void Bytecode::dump(const V4Instr *i, int address) const
case V4Instr::ConvertIntToBool:
INSTR_DUMP << '\t' << "ConvertIntToBool" << '\t' << "Input_Reg(" << i->unaryop.src << ") -> Output_Reg(" << i->unaryop.output << ')';
break;
+ case V4Instr::ConvertIntToJSValue:
+ INSTR_DUMP << '\t' << "ConvertIntToJSValue" << '\t' << "Input_Reg(" << i->unaryop.src << ") -> Output_Reg(" << i->unaryop.output << ')';
+ break;
case V4Instr::ConvertIntToNumber:
INSTR_DUMP << '\t' << "ConvertIntToNumber" << '\t' << "Input_Reg(" << i->unaryop.src << ") -> Output_Reg(" << i->unaryop.output << ')';
break;
@@ -165,12 +171,18 @@ void Bytecode::dump(const V4Instr *i, int address) const
case V4Instr::ConvertIntToVar:
INSTR_DUMP << '\t' << "ConvertIntToVar" << '\t' << "Input_Reg(" << i->unaryop.src << ") -> Output_Reg(" << i->unaryop.output << ')';
break;
+ case V4Instr::ConvertJSValueToVar:
+ INSTR_DUMP << '\t' << "ConvertJSValueToVar" << '\t' << "Input_Reg(" << i->unaryop.src << ") -> Output_Reg(" << i->unaryop.output << ')';
+ break;
case V4Instr::ConvertNumberToBool:
INSTR_DUMP << '\t' << "ConvertNumberToBool" << '\t' << "Input_Reg(" << i->unaryop.src << ") -> Output_Reg(" << i->unaryop.output << ')';
break;
case V4Instr::ConvertNumberToInt:
INSTR_DUMP << '\t' << "ConvertNumberToInt" << '\t' << "Input_Reg(" << i->unaryop.src << ") -> Output_Reg(" << i->unaryop.output << ')';
break;
+ case V4Instr::ConvertNumberToJSValue:
+ INSTR_DUMP << '\t' << "ConvertNumberToJSValue" << '\t' << "Input_Reg(" << i->unaryop.src << ") -> Output_Reg(" << i->unaryop.output << ')';
+ break;
case V4Instr::ConvertNumberToString:
INSTR_DUMP << '\t' << "ConvertNumberToString" << '\t' << "Input_Reg(" << i->unaryop.src << ") -> Output_Reg(" << i->unaryop.output << ')';
break;
@@ -186,6 +198,9 @@ void Bytecode::dump(const V4Instr *i, int address) const
case V4Instr::ConvertStringToInt:
INSTR_DUMP << '\t' << "ConvertStringToInt" << '\t' << "Input_Reg(" << i->unaryop.src << ") -> Output_Reg(" << i->unaryop.output << ')';
break;
+ case V4Instr::ConvertStringToJSValue:
+ INSTR_DUMP << '\t' << "ConvertStringToJSValue" << '\t' << "Input_Reg(" << i->unaryop.src << ") -> Output_Reg(" << i->unaryop.output << ')';
+ break;
case V4Instr::ConvertStringToNumber:
INSTR_DUMP << '\t' << "ConvertStringToNumber" << '\t' << "Input_Reg(" << i->unaryop.src << ") -> Output_Reg(" << i->unaryop.output << ')';
break;
@@ -204,6 +219,9 @@ void Bytecode::dump(const V4Instr *i, int address) const
case V4Instr::ConvertUrlToBool:
INSTR_DUMP << '\t' << "ConvertUrlToBool" << '\t' << "Input_Reg(" << i->unaryop.src << ") -> Output_Reg(" << i->unaryop.output << ')';
break;
+ case V4Instr::ConvertUrlToJSValue:
+ INSTR_DUMP << '\t' << "ConvertUrlToJSValue" << '\t' << "Input_Reg(" << i->unaryop.src << ") -> Output_Reg(" << i->unaryop.output << ')';
+ break;
case V4Instr::ConvertUrlToString:
INSTR_DUMP << '\t' << "ConvertUrlToString" << '\t' << "Input_Reg(" << i->unaryop.src << ") -> Output_Reg(" << i->unaryop.output << ')';
break;
@@ -216,6 +234,9 @@ void Bytecode::dump(const V4Instr *i, int address) const
case V4Instr::ConvertColorToBool:
INSTR_DUMP << '\t' << "ConvertColorToBool" << '\t' << "Input_Reg(" << i->unaryop.src << ") -> Output_Reg(" << i->unaryop.output << ')';
break;
+ case V4Instr::ConvertColorToJSValue:
+ INSTR_DUMP << '\t' << "ConvertColorToJSValue" << '\t' << "Input_Reg(" << i->unaryop.src << ") -> Output_Reg(" << i->unaryop.output << ')';
+ break;
case V4Instr::ConvertColorToString:
INSTR_DUMP << '\t' << "ConvertColorToString" << '\t' << "Input_Reg(" << i->unaryop.src << ") -> Output_Reg(" << i->unaryop.output << ')';
break;
@@ -228,12 +249,21 @@ void Bytecode::dump(const V4Instr *i, int address) const
case V4Instr::ConvertObjectToBool:
INSTR_DUMP << '\t' << "ConvertObjectToBool" << '\t' << "Input_Reg(" << i->unaryop.src << ") -> Output_Reg(" << i->unaryop.output << ')';
break;
+ case V4Instr::ConvertObjectToJSValue:
+ INSTR_DUMP << '\t' << "ConvertObjectToJSValue" << '\t' << "Input_Reg(" << i->unaryop.src << ") -> Output_Reg(" << i->unaryop.output << ')';
+ break;
case V4Instr::ConvertObjectToVariant:
INSTR_DUMP << '\t' << "ConvertObjectToVariant" << '\t' << "Input_Reg(" << i->unaryop.src << ") -> Output_Reg(" << i->unaryop.output << ')';
break;
case V4Instr::ConvertObjectToVar:
INSTR_DUMP << '\t' << "ConvertObjectToVar" << '\t' << "Input_Reg(" << i->unaryop.src << ") -> Output_Reg(" << i->unaryop.output << ')';
break;
+ case V4Instr::ConvertVarToJSValue:
+ INSTR_DUMP << '\t' << "ConvertVarToJSValue" << '\t' << "Input_Reg(" << i->unaryop.src << ") -> Output_Reg(" << i->unaryop.output << ')';
+ break;
+ case V4Instr::ConvertNullToJSValue:
+ INSTR_DUMP << '\t' << "ConvertNullToJSValue" << '\t' << "Input_Reg(" << i->unaryop.src << ") -> Output_Reg(" << i->unaryop.output << ')';
+ break;
case V4Instr::ConvertNullToObject:
INSTR_DUMP << '\t' << "ConvertNullToObject" << '\t' << "Input_Reg(" << i->unaryop.src << ") -> Output_Reg(" << i->unaryop.output << ')';
break;
diff --git a/src/qml/qml/v4/qv4instruction_p.h b/src/qml/qml/v4/qv4instruction_p.h
index c9e244e6b4..2e06bd0850 100644
--- a/src/qml/qml/v4/qv4instruction_p.h
+++ b/src/qml/qml/v4/qv4instruction_p.h
@@ -81,38 +81,48 @@ QT_BEGIN_NAMESPACE
F(UnaryPlusNumber, unaryop) \
F(UnaryPlusInt, unaryop) \
F(ConvertBoolToInt, unaryop) \
+ F(ConvertBoolToJSValue, unaryop) \
F(ConvertBoolToNumber, unaryop) \
F(ConvertBoolToString, unaryop) \
F(ConvertBoolToVariant, unaryop) \
F(ConvertBoolToVar, unaryop) \
F(ConvertIntToBool, unaryop) \
+ F(ConvertIntToJSValue, unaryop) \
F(ConvertIntToNumber, unaryop) \
F(ConvertIntToString, unaryop) \
F(ConvertIntToVariant, unaryop) \
F(ConvertIntToVar, unaryop) \
+ F(ConvertJSValueToVar, unaryop) \
F(ConvertNumberToBool, unaryop) \
F(ConvertNumberToInt, unaryop) \
+ F(ConvertNumberToJSValue, unaryop) \
F(ConvertNumberToString, unaryop) \
F(ConvertNumberToVariant, unaryop) \
F(ConvertNumberToVar, unaryop) \
F(ConvertStringToBool, unaryop) \
F(ConvertStringToInt, unaryop) \
+ F(ConvertStringToJSValue, unaryop) \
F(ConvertStringToNumber, unaryop) \
F(ConvertStringToUrl, unaryop) \
F(ConvertStringToColor, unaryop) \
F(ConvertStringToVariant, unaryop) \
F(ConvertStringToVar, unaryop) \
F(ConvertUrlToBool, unaryop) \
+ F(ConvertUrlToJSValue, unaryop) \
F(ConvertUrlToString, unaryop) \
F(ConvertUrlToVariant, unaryop) \
F(ConvertUrlToVar, unaryop) \
F(ConvertColorToBool, unaryop) \
+ F(ConvertColorToJSValue, unaryop) \
F(ConvertColorToString, unaryop) \
F(ConvertColorToVariant, unaryop) \
F(ConvertColorToVar, unaryop) \
F(ConvertObjectToBool, unaryop) \
+ F(ConvertObjectToJSValue, unaryop) \
F(ConvertObjectToVariant, unaryop) \
F(ConvertObjectToVar, unaryop) \
+ F(ConvertVarToJSValue, unaryop) \
+ F(ConvertNullToJSValue, unaryop) \
F(ConvertNullToObject, unaryop) \
F(ConvertNullToVariant, unaryop) \
F(ConvertNullToVar, unaryop) \
diff --git a/src/qml/qml/v4/qv4ir.cpp b/src/qml/qml/v4/qv4ir.cpp
index a111bbf6e7..bb4a0d8df0 100644
--- a/src/qml/qml/v4/qv4ir.cpp
+++ b/src/qml/qml/v4/qv4ir.cpp
@@ -65,6 +65,7 @@ const char *typeName(Type t)
case ObjectType: return "object";
case VariantType: return "variant";
case VarType: return "var";
+ case JSValueType: return "QJSValue";
case BoolType: return "bool";
case IntType: return "int";
case FloatType: return "float";
diff --git a/src/qml/qml/v4/qv4ir_p.h b/src/qml/qml/v4/qv4ir_p.h
index 485c24586c..982acc5a44 100644
--- a/src/qml/qml/v4/qv4ir_p.h
+++ b/src/qml/qml/v4/qv4ir_p.h
@@ -148,6 +148,7 @@ enum Type {
ObjectType,
VariantType,
VarType,
+ JSValueType,
FirstNumberType,
BoolType = FirstNumberType,
diff --git a/src/qml/qml/v4/qv4irbuilder.cpp b/src/qml/qml/v4/qv4irbuilder.cpp
index 52f0696be9..47acaaf67c 100644
--- a/src/qml/qml/v4/qv4irbuilder.cpp
+++ b/src/qml/qml/v4/qv4irbuilder.cpp
@@ -48,6 +48,8 @@
DEFINE_BOOL_CONFIG_OPTION(qmlVerboseCompiler, QML_VERBOSE_COMPILER)
+Q_DECLARE_METATYPE(QJSValue)
+
QT_BEGIN_NAMESPACE
using namespace QQmlJS;
@@ -81,6 +83,8 @@ static IR::Type irTypeFromVariantType(int t, QQmlEnginePrivate *engine, const QM
return IR::SGAnchorLineType;
} else if (engine->metaObjectForType(t)) {
return IR::ObjectType;
+ } else if (t == qMetaTypeId<QJSValue>()) {
+ return IR::JSValueType;
}
return IR::InvalidType;
diff --git a/src/qml/qml/v4/qv4program_p.h b/src/qml/qml/v4/qv4program_p.h
index 3fb1670411..d859a83abb 100644
--- a/src/qml/qml/v4/qv4program_p.h
+++ b/src/qml/qml/v4/qv4program_p.h
@@ -103,7 +103,8 @@ enum QQmlRegisterType {
QUrlType,
QVariantType,
QColorType,
- V8HandleType
+ V8HandleType,
+ QJSValueType
};
const char *QV4Program::data() const
diff --git a/src/qml/qml/v8/qv8engine.cpp b/src/qml/qml/v8/qv8engine.cpp
index 275b648ee4..c075fc9d1b 100644
--- a/src/qml/qml/v8/qv8engine.cpp
+++ b/src/qml/qml/v8/qv8engine.cpp
@@ -229,6 +229,9 @@ QVariant QV8Engine::toVariant(v8::Handle<v8::Value> value, int typeHint)
if (typeHint == QMetaType::QJsonValue)
return QVariant::fromValue(jsonValueFromJS(value));
+ if (typeHint == qMetaTypeId<QJSValue>())
+ return QVariant::fromValue(scriptValueFromInternal(value));
+
if (value->IsObject()) {
QV8ObjectResource *r = (QV8ObjectResource *)value->ToObject()->GetExternalResource();
if (r) {
diff --git a/src/qml/qml/v8/qv8qobjectwrapper.cpp b/src/qml/qml/v8/qv8qobjectwrapper.cpp
index aab66e33a2..f540ce126b 100644
--- a/src/qml/qml/v8/qv8qobjectwrapper.cpp
+++ b/src/qml/qml/v8/qv8qobjectwrapper.cpp
@@ -433,6 +433,10 @@ static v8::Handle<v8::Value> LoadProperty(QV8Engine *engine, QObject *object,
QQmlV8Handle handle;
ReadFunction(object, property, &handle, notifier);
return handle.toHandle();
+ } else if (property.propType == qMetaTypeId<QJSValue>()) {
+ QJSValue v;
+ ReadFunction(object, property, &v, notifier);
+ return QJSValuePrivate::get(v)->asV8Value(engine);
} else if (property.isQVariant()) {
QVariant v;
ReadFunction(object, property, &v, notifier);
@@ -590,8 +594,8 @@ static inline void StoreProperty(QV8Engine *engine, QObject *object, QQmlPropert
QQmlBinding *newBinding = 0;
if (value->IsFunction()) {
if (value->ToObject()->GetHiddenValue(engine->bindingFlagKey()).IsEmpty()) {
- if (!property->isVMEProperty()) {
- // assigning a JS function to a non-var-property is not allowed.
+ if (!property->isVMEProperty() && property->propType != qMetaTypeId<QJSValue>()) {
+ // assigning a JS function to a non var or QJSValue property or is not allowed.
QString error = QLatin1String("Cannot assign JavaScript function to ") +
QLatin1String(QMetaType::typeName(property->propType));
v8::ThrowException(v8::Exception::Error(engine->toString(error)));
@@ -647,6 +651,8 @@ static inline void StoreProperty(QV8Engine *engine, QObject *object, QQmlPropert
PROPERTY_STORE(QVariant, QVariant());
} else if (value->IsUndefined() && property->propType == QMetaType::QJsonValue) {
PROPERTY_STORE(QJsonValue, QJsonValue(QJsonValue::Undefined));
+ } else if (!newBinding && property->propType == qMetaTypeId<QJSValue>()) {
+ PROPERTY_STORE(QJSValue, engine->scriptValueFromInternal(value));
} else if (value->IsUndefined()) {
QString error = QLatin1String("Cannot assign [undefined] to ") +
QLatin1String(QMetaType::typeName(property->propType));