aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorChris Adams <christopher.adams@nokia.com>2012-08-14 11:44:49 +1000
committerQt by Nokia <qt-info@nokia.com>2012-08-28 04:32:48 +0200
commit70a2c0491d66aa05f9e9e67f8a845f4df84da857 (patch)
tree08d7828cfb6950926e1176ee420d5e15dedd9817 /src
parent3912bbaceab166eb116447311eb16453e4f26edf (diff)
Refactor singleton type registration code
Previously each singleton type was registered as an implicit separate import. This commit changes the code so that these types are treated just like any other type in the registration sense. It also ensures that singleton types are instantiated per-engine. Change-Id: I5c81c4ca5bf65210f7125d74a62a282a21838068 Reviewed-by: Matthew Vogt <matthew.vogt@nokia.com>
Diffstat (limited to 'src')
-rw-r--r--src/qml/qml/qqml.h9
-rw-r--r--src/qml/qml/qqmlcompiler.cpp2
-rw-r--r--src/qml/qml/qqmlengine.cpp43
-rw-r--r--src/qml/qml/qqmlengine_p.h4
-rw-r--r--src/qml/qml/qqmlimport.cpp22
-rw-r--r--src/qml/qml/qqmlimport_p.h2
-rw-r--r--src/qml/qml/qqmlmetatype.cpp345
-rw-r--r--src/qml/qml/qqmlmetatype_p.h86
-rw-r--r--src/qml/qml/qqmlprivate.h5
-rw-r--r--src/qml/qml/qqmltypeloader.cpp4
-rw-r--r--src/qml/qml/qqmltypenamecache.cpp24
-rw-r--r--src/qml/qml/qqmltypenamecache_p.h5
-rw-r--r--src/qml/qml/v4/qv4bindings.cpp22
-rw-r--r--src/qml/qml/v4/qv4compiler.cpp10
-rw-r--r--src/qml/qml/v4/qv4instruction.cpp4
-rw-r--r--src/qml/qml/v4/qv4instruction_p.h2
-rw-r--r--src/qml/qml/v4/qv4ir.cpp8
-rw-r--r--src/qml/qml/v4/qv4ir_p.h14
-rw-r--r--src/qml/qml/v4/qv4irbuilder.cpp12
-rw-r--r--src/qml/qml/v8/qv8typewrapper.cpp174
20 files changed, 370 insertions, 427 deletions
diff --git a/src/qml/qml/qqml.h b/src/qml/qml/qqml.h
index a10ed0c5e8..105274d3e3 100644
--- a/src/qml/qml/qqml.h
+++ b/src/qml/qml/qqml.h
@@ -441,22 +441,25 @@ inline int qmlRegisterSingletonType(const char *uri, int versionMajor, int versi
uri, versionMajor, versionMinor, typeName,
- callback, 0, 0
+ callback, 0, 0, 0, 0
};
return QQmlPrivate::qmlregister(QQmlPrivate::SingletonRegistration, &api);
}
+static const int CurrentSingletonTypeRegistrationVersion = 2;
template <typename T>
inline int qmlRegisterSingletonType(const char *uri, int versionMajor, int versionMinor, const char *typeName,
QObject *(*callback)(QQmlEngine *, QJSEngine *))
{
+ QML_GETTYPENAMES
+
QQmlPrivate::RegisterSingletonType api = {
- 1,
+ CurrentSingletonTypeRegistrationVersion,
uri, versionMajor, versionMinor, typeName,
- 0, callback, &T::staticMetaObject
+ 0, callback, &T::staticMetaObject, qRegisterNormalizedMetaType<T *>(pointerName.constData()), 0
};
return QQmlPrivate::qmlregister(QQmlPrivate::SingletonRegistration, &api);
diff --git a/src/qml/qml/qqmlcompiler.cpp b/src/qml/qml/qqmlcompiler.cpp
index c9f66a4ea0..88312be33e 100644
--- a/src/qml/qml/qqmlcompiler.cpp
+++ b/src/qml/qml/qqmlcompiler.cpp
@@ -896,7 +896,7 @@ void QQmlCompiler::compileTree(QQmlScript::Object *tree)
output->importCache->add(qualifier, scriptIndex++, enclosingNamespace);
}
- unit->imports().populateCache(output->importCache, engine);
+ unit->imports().populateCache(output->importCache);
if (!buildObject(tree, BindingContext()) || !completeComponentBuild())
return;
diff --git a/src/qml/qml/qqmlengine.cpp b/src/qml/qml/qqmlengine.cpp
index 6ebd6b7666..b3952a787a 100644
--- a/src/qml/qml/qqmlengine.cpp
+++ b/src/qml/qml/qqmlengine.cpp
@@ -462,10 +462,6 @@ QQmlEnginePrivate::~QQmlEnginePrivate()
(*iter)->release();
for(QHash<QPair<QQmlType *, int>, QQmlPropertyCache *>::Iterator iter = typePropertyCache.begin(); iter != typePropertyCache.end(); ++iter)
(*iter)->release();
- for (QHash<QQmlMetaType::SingletonType, QQmlMetaType::SingletonInstance *>::Iterator iter = singletonTypeInstances.begin(); iter != singletonTypeInstances.end(); ++iter) {
- delete (*iter)->qobjectApi;
- delete *iter;
- }
for (QHash<int, QQmlCompiledData *>::Iterator iter = m_compositeTypes.begin(); iter != m_compositeTypes.end(); ++iter)
iter.value()->isRegisteredWithEngine = false;
}
@@ -743,21 +739,13 @@ QQmlEngine::~QQmlEngine()
// may be required to handle the destruction signal.
QQmlContextData::get(rootContext())->emitDestruction();
- // if we are the parent of any of the qobject singleton type instances,
- // we need to remove them from our internal list, in order to prevent
- // a segfault in engine private dtor.
- QList<QQmlMetaType::SingletonType> keys = d->singletonTypeInstances.keys();
- QObject *currQObjectApi = 0;
- QQmlMetaType::SingletonInstance *currInstance = 0;
- foreach (const QQmlMetaType::SingletonType &key, keys) {
- currInstance = d->singletonTypeInstances.value(key);
- currQObjectApi = currInstance->qobjectApi;
- if (this->children().contains(currQObjectApi)) {
- delete currQObjectApi;
- delete currInstance;
- d->singletonTypeInstances.remove(key);
- }
- }
+ // clean up all singleton type instances which we own.
+ // we do this here and not in the private dtor since otherwise a crash can
+ // occur (if we are the QObject parent of the QObject singleton instance)
+ // XXX TODO: performance -- store list of singleton types separately?
+ QList<QQmlType*> singletonTypes = QQmlMetaType::qmlSingletonTypes();
+ foreach (QQmlType *currType, singletonTypes)
+ currType->singletonInstanceInfo()->destroy(this);
if (d->incubationController)
d->incubationController->d = 0;
@@ -1890,23 +1878,6 @@ QQmlPropertyCache *QQmlEnginePrivate::createCache(QQmlType *type, int minorVersi
return raw;
}
-QQmlMetaType::SingletonInstance *
-QQmlEnginePrivate::singletonTypeInstance(const QQmlMetaType::SingletonType &module)
-{
- Locker locker(this);
-
- QQmlMetaType::SingletonInstance *a = singletonTypeInstances.value(module);
- if (!a) {
- a = new QQmlMetaType::SingletonInstance;
- a->scriptCallback = module.script;
- a->qobjectCallback = module.qobject;
- a->instanceMetaObject = module.instanceMetaObject;
- singletonTypeInstances.insert(module, a);
- }
-
- return a;
-}
-
bool QQmlEnginePrivate::isQObject(int t)
{
Locker locker(this);
diff --git a/src/qml/qml/qqmlengine_p.h b/src/qml/qml/qqmlengine_p.h
index fb7109f507..e014cfffc4 100644
--- a/src/qml/qml/qqmlengine_p.h
+++ b/src/qml/qml/qqmlengine_p.h
@@ -221,9 +221,6 @@ public:
inline static void deleteInEngineThread(QQmlEngine *, T *);
// These methods may be called from the loader thread
- QQmlMetaType::SingletonInstance *singletonTypeInstance(const QQmlMetaType::SingletonType &module);
-
- // These methods may be called from the loader thread
inline QQmlPropertyCache *cache(QObject *obj);
inline QQmlPropertyCache *cache(const QMetaObject *);
inline QQmlPropertyCache *cache(QQmlType *, int, QQmlError &error);
@@ -303,7 +300,6 @@ private:
// These members must be protected by a QQmlEnginePrivate::Locker as they are required by
// the threaded loader. Only access them through their respective accessor methods.
- QHash<QQmlMetaType::SingletonType, QQmlMetaType::SingletonInstance *> singletonTypeInstances;
QHash<const QMetaObject *, QQmlPropertyCache *> propertyCache;
QHash<QPair<QQmlType *, int>, QQmlPropertyCache *> typePropertyCache;
QHash<int, int> m_qmlLists;
diff --git a/src/qml/qml/qqmlimport.cpp b/src/qml/qml/qqmlimport.cpp
index 739492b3d3..63f49a2a03 100644
--- a/src/qml/qml/qqmlimport.cpp
+++ b/src/qml/qml/qqmlimport.cpp
@@ -290,23 +290,15 @@ QUrl QQmlImports::baseUrl() const
return d->baseUrl;
}
-void QQmlImports::populateCache(QQmlTypeNameCache *cache, QQmlEngine *engine) const
+void QQmlImports::populateCache(QQmlTypeNameCache *cache) const
{
const QQmlImportNamespace &set = d->unqualifiedset;
for (int ii = set.imports.count() - 1; ii >= 0; --ii) {
const QQmlImportNamespace::Import *import = set.imports.at(ii);
QQmlTypeModule *module = QQmlMetaType::typeModule(import->uri, import->majversion);
- if (module)
+ if (module) {
cache->m_anonymousImports.append(QQmlTypeModuleVersion(module, import->minversion));
-
- QQmlMetaType::SingletonType singletonType = QQmlMetaType::singletonType(import->uri, import->majversion,
- import->minversion);
- if (singletonType.script || singletonType.qobject) {
- QQmlEnginePrivate *ep = QQmlEnginePrivate::get(engine);
- QQmlMetaType::SingletonInstance *apiInstance = ep->singletonTypeInstance(singletonType);
-
- cache->addSingletonType(singletonType.typeName, apiInstance);
}
}
@@ -321,16 +313,6 @@ void QQmlImports::populateCache(QQmlTypeNameCache *cache, QQmlEngine *engine) co
QQmlTypeNameCache::Import &typeimport = cache->m_namedImports[set.prefix];
typeimport.modules.append(QQmlTypeModuleVersion(module, import->minversion));
}
-
- QQmlMetaType::SingletonType singletonType = QQmlMetaType::singletonType(import->uri, import->majversion,
- import->minversion);
- if (singletonType.script || singletonType.qobject) {
- QQmlEnginePrivate *ep = QQmlEnginePrivate::get(engine);
- QQmlMetaType::SingletonInstance *apiInstance = ep->singletonTypeInstance(singletonType);
-
- cache->add(set.prefix);
- cache->addSingletonType(singletonType.typeName, apiInstance, set.prefix);
- }
}
}
}
diff --git a/src/qml/qml/qqmlimport_p.h b/src/qml/qml/qqmlimport_p.h
index 2a1fe48b6e..192e706245 100644
--- a/src/qml/qml/qqmlimport_p.h
+++ b/src/qml/qml/qqmlimport_p.h
@@ -112,7 +112,7 @@ public:
const QString &uri, int vmaj, int vmin,
QString *qmldirFilePath, QString *url);
- void populateCache(QQmlTypeNameCache *cache, QQmlEngine *) const;
+ void populateCache(QQmlTypeNameCache *cache) const;
struct ScriptReference
{
diff --git a/src/qml/qml/qqmlmetatype.cpp b/src/qml/qml/qqmlmetatype.cpp
index 1b94365d03..284269bf63 100644
--- a/src/qml/qml/qqmlmetatype.cpp
+++ b/src/qml/qml/qqmlmetatype.cpp
@@ -94,36 +94,6 @@ struct QQmlMetaTypeData
typedef QHash<VersionedUri, QQmlTypeModule *> TypeModules;
TypeModules uriToModule;
- struct SingletonTypeList {
- SingletonTypeList() : sorted(true) {}
- QList<QQmlMetaType::SingletonType> singletonTypes;
- bool sorted;
- };
- typedef QStringHash<SingletonTypeList> SingletonTypes;
- SingletonTypes singletonTypes;
- int singletonTypeCount;
-
- bool singletonTypeExists(const QString &uri, const QString &typeName, int major, int minor)
- {
- QQmlMetaTypeData::SingletonTypeList *apiList = singletonTypes.value(uri);
- if (apiList) {
- for (int i=0 ; i < apiList->singletonTypes.size() ; ++i) {
- const QQmlMetaType::SingletonType &import = apiList->singletonTypes.at(i);
- if (import.major == major && import.minor == minor && typeName == import.typeName)
- return true;
- }
- }
-
- return false;
- }
-
- bool typeExists(const QString &uri, const QString &typeName, int major, int minor)
- {
- QQmlMetaTypeData::VersionedUri versionedUri(uri, major);
- QQmlTypeModule *module = uriToModule.value(versionedUri);
- return module && module->typeNoLock(typeName, minor) != 0;
- }
-
QBitArray objects;
QBitArray interfaces;
QBitArray lists;
@@ -162,7 +132,6 @@ static uint qHash(const QQmlMetaTypeData::VersionedUri &v)
}
QQmlMetaTypeData::QQmlMetaTypeData()
-: singletonTypeCount(0)
{
}
@@ -176,6 +145,7 @@ class QQmlTypePrivate
{
public:
QQmlTypePrivate();
+ ~QQmlTypePrivate();
void init() const;
void initEnums() const;
@@ -213,6 +183,7 @@ public:
mutable bool m_haveSuperType:1;
mutable QList<QQmlProxyMetaObject::ProxyData> m_metaObjects;
mutable QStringHash<int> m_enums;
+ QQmlType::SingletonInstanceInfo *m_singletonInstanceInfo;
static QHash<const QMetaObject *, int> m_attachedPropertyIds;
};
@@ -238,6 +209,43 @@ static QHashedString moduleFromUtf8(const char *module)
return lastModuleStr;
}
+void QQmlType::SingletonInstanceInfo::init(QQmlEngine *e)
+{
+ if (scriptCallback && scriptApi(e).isUndefined()) {
+ setScriptApi(e, scriptCallback(e, e));
+ } else if (qobjectCallback && !qobjectApi(e)) {
+ setQObjectApi(e, qobjectCallback(e, e));
+ }
+}
+
+void QQmlType::SingletonInstanceInfo::destroy(QQmlEngine *e)
+{
+ // cleans up the engine-specific singleton instances if they exist.
+ scriptApis.remove(e);
+ QObject *o = qobjectApis.take(e);
+ delete o;
+}
+
+void QQmlType::SingletonInstanceInfo::setQObjectApi(QQmlEngine *e, QObject *o)
+{
+ qobjectApis.insert(e, o);
+}
+
+QObject *QQmlType::SingletonInstanceInfo::qobjectApi(QQmlEngine *e) const
+{
+ return qobjectApis.value(e);
+}
+
+void QQmlType::SingletonInstanceInfo::setScriptApi(QQmlEngine *e, QJSValue v)
+{
+ scriptApis.insert(e, v);
+}
+
+QJSValue QQmlType::SingletonInstanceInfo::scriptApi(QQmlEngine *e) const
+{
+ return scriptApis.value(e);
+}
+
QHash<const QMetaObject *, int> QQmlTypePrivate::m_attachedPropertyIds;
QQmlTypePrivate::QQmlTypePrivate()
@@ -245,10 +253,14 @@ QQmlTypePrivate::QQmlTypePrivate()
m_superType(0), m_allocationSize(0), m_newFunc(0), m_baseMetaObject(0), m_attachedPropertiesFunc(0),
m_attachedPropertiesType(0), m_parserStatusCast(-1), m_propertyValueSourceCast(-1),
m_propertyValueInterceptorCast(-1), m_extFunc(0), m_extMetaObject(0), m_index(-1), m_customParser(0),
- m_isSetup(false), m_isEnumSetup(false), m_haveSuperType(false)
+ m_isSetup(false), m_isEnumSetup(false), m_haveSuperType(false), m_singletonInstanceInfo(0)
{
}
+QQmlTypePrivate::~QQmlTypePrivate()
+{
+ delete m_singletonInstanceInfo;
+}
QQmlType::QQmlType(int index, const QQmlPrivate::RegisterInterface &interface)
: d(new QQmlTypePrivate)
@@ -264,6 +276,34 @@ QQmlType::QQmlType(int index, const QQmlPrivate::RegisterInterface &interface)
d->m_version_min = 0;
}
+QQmlType::QQmlType(int index, const QString &elementName, const QQmlPrivate::RegisterSingletonType &type)
+: d(new QQmlTypePrivate)
+{
+ d->m_elementName = elementName;
+ d->m_module = moduleFromUtf8(type.uri);
+
+ d->m_version_maj = type.versionMajor;
+ d->m_version_min = type.versionMinor;
+
+ if (type.qobjectApi) {
+ if (type.version >= 1) // static metaobject added in version 1
+ d->m_baseMetaObject = type.instanceMetaObject;
+ if (type.version >= 2) // typeId added in version 2
+ d->m_typeId = type.typeId;
+ if (type.version >= 2) // revisions added in version 2
+ d->m_revision = type.revision;
+ }
+
+ d->m_newFunc = 0;
+ d->m_index = index;
+
+ d->m_singletonInstanceInfo = new SingletonInstanceInfo;
+ d->m_singletonInstanceInfo->scriptCallback = type.scriptApi;
+ d->m_singletonInstanceInfo->qobjectCallback = type.qobjectApi;
+ d->m_singletonInstanceInfo->typeName = QString::fromUtf8(type.typeName);
+ d->m_singletonInstanceInfo->instanceMetaObject = (type.qobjectApi && type.version >= 1) ? type.instanceMetaObject : 0;
+}
+
QQmlType::QQmlType(int index, const QString &elementName, const QQmlPrivate::RegisterType &type)
: d(new QQmlTypePrivate)
{
@@ -337,7 +377,7 @@ bool QQmlType::availableInVersion(const QHashedStringRef &module, int vmajor, in
// returns the nearest _registered_ super class
QQmlType *QQmlType::superType() const
{
- if (!d->m_haveSuperType) {
+ if (!d->m_haveSuperType && d->m_baseMetaObject) {
const QMetaObject *mo = d->m_baseMetaObject->superClass();
while (mo && !d->m_superType) {
d->m_superType = QQmlMetaType::qmlType(mo, d->m_module, d->m_version_maj, d->m_version_min);
@@ -443,9 +483,14 @@ void QQmlTypePrivate::init() const
if (m_isSetup)
return;
+ const QMetaObject *mo = m_baseMetaObject;
+ if (!mo) {
+ // singleton type without metaobject information
+ return;
+ }
+
// Setup extended meta object
// XXX - very inefficient
- const QMetaObject *mo = m_baseMetaObject;
if (m_extFunc) {
QMetaObjectBuilder builder;
clone(builder, m_extMetaObject, m_extMetaObject, m_extMetaObject);
@@ -514,7 +559,8 @@ void QQmlTypePrivate::initEnums() const
QWriteLocker lock(metaTypeDataLock());
if (m_isEnumSetup) return;
- insertEnums(m_baseMetaObject);
+ if (m_baseMetaObject) // could be singleton type without metaobject
+ insertEnums(m_baseMetaObject);
m_isEnumSetup = true;
}
@@ -540,6 +586,8 @@ void QQmlTypePrivate::insertEnums(const QMetaObject *metaObject) const
QByteArray QQmlType::typeName() const
{
+ if (d->m_singletonInstanceInfo)
+ return d->m_singletonInstanceInfo->typeName.toUtf8();
if (d->m_baseMetaObject)
return d->m_baseMetaObject->className();
else
@@ -590,6 +638,11 @@ void QQmlType::create(QObject **out, void **memory, size_t additionalMemory) con
*memory = ((char *)rv) + d->m_allocationSize;
}
+QQmlType::SingletonInstanceInfo *QQmlType::singletonInstanceInfo() const
+{
+ return d->m_singletonInstanceInfo;
+}
+
QQmlCustomParser *QQmlType::customParser() const
{
return d->m_customParser;
@@ -622,6 +675,11 @@ bool QQmlType::isExtendedType() const
return !d->m_metaObjects.isEmpty();
}
+bool QQmlType::isSingleton() const
+{
+ return d->m_singletonInstanceInfo != 0;
+}
+
bool QQmlType::isInterface() const
{
return d->m_isInterface;
@@ -800,9 +858,9 @@ void QQmlTypeModulePrivate::add(QQmlType *type)
list.append(type);
}
-QQmlType *QQmlTypeModule::typeNoLock(const QString &name, int minor)
+QQmlType *QQmlTypeModule::type(const QHashedStringRef &name, int minor)
{
- // Expected that the caller has already handled locking metaTypeDataLock
+ QReadLocker lock(metaTypeDataLock());
QList<QQmlType *> *types = d->typeHash.value(name);
if (!types) return 0;
@@ -814,7 +872,7 @@ QQmlType *QQmlTypeModule::typeNoLock(const QString &name, int minor)
return 0;
}
-QQmlType *QQmlTypeModule::type(const QHashedStringRef &name, int minor)
+QQmlType *QQmlTypeModule::type(const QHashedV8String &name, int minor)
{
QReadLocker lock(metaTypeDataLock());
@@ -828,18 +886,18 @@ QQmlType *QQmlTypeModule::type(const QHashedStringRef &name, int minor)
return 0;
}
-QQmlType *QQmlTypeModule::type(const QHashedV8String &name, int minor)
+QList<QQmlType*> QQmlTypeModule::singletonTypes(int minor) const
{
QReadLocker lock(metaTypeDataLock());
- QList<QQmlType *> *types = d->typeHash.value(name);
- if (!types) return 0;
-
- for (int ii = 0; ii < types->count(); ++ii)
- if (types->at(ii)->minorVersion() <= minor)
- return types->at(ii);
+ QList<QQmlType *> retn;
+ for (int ii = 0; ii < d->types.count(); ++ii) {
+ QQmlType *curr = d->types.at(ii);
+ if (curr->isSingleton() && curr->minorVersion() <= minor)
+ retn.append(curr);
+ }
- return 0;
+ return retn;
}
@@ -929,49 +987,63 @@ int registerInterface(const QQmlPrivate::RegisterInterface &interface)
return index;
}
-int registerType(const QQmlPrivate::RegisterType &type)
+QString registrationTypeString(QQmlType::RegistrationType typeType)
{
- if (type.elementName) {
- for (int ii = 0; type.elementName[ii]; ++ii) {
- if (!isalnum(type.elementName[ii])) {
- qWarning("qmlRegisterType(): Invalid QML element name \"%s\"", type.elementName);
- return -1;
+ QString typeStr;
+ if (typeType == QQmlType::CppType)
+ typeStr = QStringLiteral("element");
+ else if (typeType == QQmlType::SingletonType)
+ typeStr = QStringLiteral("singleton type");
+ return typeStr;
+}
+
+// NOTE: caller must hold a QWriteLocker on "data"
+bool checkRegistration(QQmlType::RegistrationType typeType, QQmlMetaTypeData *data, const char *uri, const QString &typeName)
+{
+ if (!typeName.isEmpty()) {
+ int typeNameLen = typeName.length();
+ for (int ii = 0; ii < typeNameLen; ++ii) {
+ if (!typeName.at(ii).isLetterOrNumber()) {
+ QString failure(QCoreApplication::translate("qmlRegisterType", "Invalid QML %1 name \"%2\""));
+ data->typeRegistrationFailures.append(failure.arg(registrationTypeString(typeType)).arg(typeName));
+ return false;
}
}
}
- QWriteLocker lock(metaTypeDataLock());
- QQmlMetaTypeData *data = metaTypeData();
-
- QString elementName = QString::fromUtf8(type.elementName);
-
- if (type.uri && type.elementName) {
- QString nameSpace = moduleFromUtf8(type.uri);
-
- if (data->singletonTypeExists(nameSpace, elementName, type.versionMajor, type.versionMinor)) {
- qWarning("Cannot register type %s in uri %s %d.%d (a conflicting singleton type already exists)", qPrintable(elementName), qPrintable(nameSpace), type.versionMajor, type.versionMinor);
- return -1;
- }
+ if (uri && !typeName.isEmpty()) {
+ QString nameSpace = moduleFromUtf8(uri);
if (!data->typeRegistrationNamespace.isEmpty()) {
// We can only install types into the registered namespace
if (nameSpace != data->typeRegistrationNamespace) {
QString failure(QCoreApplication::translate("qmlRegisterType",
- "Cannot install element '%1' into unregistered namespace '%2'"));
- data->typeRegistrationFailures.append(failure.arg(elementName).arg(nameSpace));
- return -1;
+ "Cannot install %1 '%2' into unregistered namespace '%3'"));
+ data->typeRegistrationFailures.append(failure.arg(registrationTypeString(typeType)).arg(typeName).arg(nameSpace));
+ return false;
}
} else if (data->typeRegistrationNamespace != nameSpace) {
// Is the target namespace protected against further registrations?
if (data->protectedNamespaces.contains(nameSpace)) {
QString failure(QCoreApplication::translate("qmlRegisterType",
- "Cannot install element '%1' into protected namespace '%2'"));
- data->typeRegistrationFailures.append(failure.arg(elementName).arg(nameSpace));
- return -1;
+ "Cannot install %1 '%2' into protected namespace '%3'"));
+ data->typeRegistrationFailures.append(failure.arg(registrationTypeString(typeType)).arg(typeName).arg(nameSpace));
+ return false;
}
}
}
+ return true;
+}
+
+int registerType(const QQmlPrivate::RegisterType &type)
+{
+ QWriteLocker lock(metaTypeDataLock());
+ QQmlMetaTypeData *data = metaTypeData();
+ QString elementName = QString::fromUtf8(type.elementName);
+ if (!checkRegistration(QQmlType::CppType, data, type.uri, elementName))
+ return -1;
+
int index = data->types.count();
QQmlType *dtype = new QQmlType(index, elementName, type);
@@ -1008,39 +1080,44 @@ int registerType(const QQmlPrivate::RegisterType &type)
return index;
}
-int registerSingletonType(const QQmlPrivate::RegisterSingletonType &api)
+int registerSingletonType(const QQmlPrivate::RegisterSingletonType &type)
{
QWriteLocker lock(metaTypeDataLock());
-
QQmlMetaTypeData *data = metaTypeData();
- QString uri = QString::fromUtf8(api.uri);
- QQmlMetaType::SingletonType import;
- import.major = api.versionMajor;
- import.minor = api.versionMinor;
- import.script = api.scriptApi;
- import.qobject = api.qobjectApi;
- Q_ASSERT(api.typeName);
- import.typeName = QString::fromUtf8(api.typeName);
- import.instanceMetaObject = (api.qobjectApi && api.version >= 1) ? api.instanceMetaObject : 0; // BC with version 0.
-
- if (data->singletonTypeExists(uri, import.typeName, import.major, import.minor)) {
- qWarning("Cannot register singleton type %s in uri %s %d.%d (a conflicting singleton type already exists)", qPrintable(import.typeName), qPrintable(uri), import.major, import.minor);
- return -1;
- } else if (data->typeExists(uri, import.typeName, import.major, import.minor)) {
- qWarning("Cannot register singleton type %s in uri %s %d.%d (a conflicting type already exists)", qPrintable(import.typeName), qPrintable(uri), import.major, import.minor);
+ QString typeName = QString::fromUtf8(type.typeName);
+ if (!checkRegistration(QQmlType::SingletonType, data, type.uri, typeName))
return -1;
+
+ int index = data->types.count();
+
+ QQmlType *dtype = new QQmlType(index, typeName, type);
+
+ data->types.append(dtype);
+ data->idToType.insert(dtype->typeId(), dtype);
+
+ if (!dtype->elementName().isEmpty())
+ data->nameToType.insertMulti(dtype->elementName(), dtype);
+
+ if (dtype->baseMetaObject())
+ data->metaObjectToType.insertMulti(dtype->baseMetaObject(), dtype);
+
+ if (type.typeId) {
+ if (data->objects.size() <= type.typeId)
+ data->objects.resize(type.typeId + 16);
+ data->objects.setBit(type.typeId, true);
}
- int index = data->singletonTypeCount++;
+ if (!dtype->module().isEmpty()) {
+ const QHashedString &mod = dtype->module();
- QQmlMetaTypeData::SingletonTypeList *apiList = data->singletonTypes.value(uri);
- if (!apiList) {
- QQmlMetaTypeData::SingletonTypeList apis;
- apis.singletonTypes << import;
- data->singletonTypes.insert(uri, apis);
- } else {
- apiList->singletonTypes << import;
- apiList->sorted = false;
+ QQmlMetaTypeData::VersionedUri versionedUri(mod, type.versionMajor);
+ QQmlTypeModule *module = data->uriToModule.value(versionedUri);
+ if (!module) {
+ module = new QQmlTypeModule;
+ module->d->uri = versionedUri;
+ data->uriToModule.insert(versionedUri, module);
+ }
+ module->d->add(dtype);
}
return index;
@@ -1113,18 +1190,12 @@ bool QQmlMetaType::isAnyModule(const QString &uri)
QReadLocker lock(metaTypeDataLock());
QQmlMetaTypeData *data = metaTypeData();
- // first, check Types
for (QQmlMetaTypeData::TypeModules::ConstIterator iter = data->uriToModule.begin();
iter != data->uriToModule.end(); ++iter) {
if ((*iter)->module() == uri)
return true;
}
- // then, check SingletonTypes
- QQmlMetaTypeData::SingletonTypeList *apiList = data->singletonTypes.value(uri);
- if (apiList)
- return true;
-
return false;
}
@@ -1148,15 +1219,6 @@ bool QQmlMetaType::isModule(const QString &module, int versionMajor, int version
if (tm && tm->minimumMinorVersion() <= versionMinor && tm->maximumMinorVersion() >= versionMinor)
return true;
- // then, check SingletonTypes
- QQmlMetaTypeData::SingletonTypeList *apiList = data->singletonTypes.value(module);
- if (apiList) {
- foreach (const QQmlMetaType::SingletonType &mApi, apiList->singletonTypes) {
- if (mApi.major == versionMajor && mApi.minor == versionMinor) // XXX is this correct?
- return true;
- }
- }
-
return false;
}
@@ -1174,48 +1236,6 @@ QList<QQmlPrivate::AutoParentFunction> QQmlMetaType::parentFunctions()
return data->parentFunctions;
}
-static bool operator<(const QQmlMetaType::SingletonType &lhs, const QQmlMetaType::SingletonType &rhs)
-{
- return lhs.major < rhs.major || (lhs.major == rhs.major && lhs.minor < rhs.minor);
-}
-
-QQmlMetaType::SingletonType
-QQmlMetaType::singletonType(const QString &uri, int versionMajor, int versionMinor)
-{
- QReadLocker lock(metaTypeDataLock());
- QQmlMetaTypeData *data = metaTypeData();
-
- QQmlMetaTypeData::SingletonTypeList *apiList = data->singletonTypes.value(uri);
- if (!apiList)
- return SingletonType();
-
- if (apiList->sorted == false) {
- qSort(apiList->singletonTypes.begin(), apiList->singletonTypes.end());
- apiList->sorted = true;
- }
-
- for (int ii = apiList->singletonTypes.count() - 1; ii >= 0; --ii) {
- const SingletonType &import = apiList->singletonTypes.at(ii);
- if (import.major == versionMajor && import.minor <= versionMinor)
- return import;
- }
-
- return SingletonType();
-}
-
-QHash<QString, QList<QQmlMetaType::SingletonType> > QQmlMetaType::singletonTypes()
-{
- QReadLocker lock(metaTypeDataLock());
- QQmlMetaTypeData *data = metaTypeData();
-
- QHash<QString, QList<SingletonType> > singletonTypes;
- QStringHash<QQmlMetaTypeData::SingletonTypeList>::ConstIterator it = data->singletonTypes.begin();
- for (; it != data->singletonTypes.end(); ++it)
- singletonTypes[it.key()] = it.value().singletonTypes;
-
- return singletonTypes;
-}
-
QObject *QQmlMetaType::toQObject(const QVariant &v, bool *ok)
{
if (!isQObject(v.userType())) {
@@ -1521,6 +1541,25 @@ QList<QQmlType*> QQmlMetaType::qmlTypes()
return data->nameToType.values();
}
+/*!
+ Returns the list of registered QML singleton types.
+*/
+QList<QQmlType*> QQmlMetaType::qmlSingletonTypes()
+{
+ QReadLocker lock(metaTypeDataLock());
+ QQmlMetaTypeData *data = metaTypeData();
+
+ QList<QQmlType*> alltypes = data->nameToType.values();
+ QList<QQmlType*> retn;
+ foreach (QQmlType* t, alltypes) {
+ if (t->isSingleton()) {
+ retn.append(t);
+ }
+ }
+
+ return retn;
+}
+
int QQmlMetaType::QQuickAnchorLineMetaTypeId()
{
static int id = 0;
diff --git a/src/qml/qml/qqmlmetatype_p.h b/src/qml/qml/qqmlmetatype_p.h
index ad1ceb8052..dadd01bb4c 100644
--- a/src/qml/qml/qqmlmetatype_p.h
+++ b/src/qml/qml/qqmlmetatype_p.h
@@ -64,6 +64,7 @@
QT_BEGIN_NAMESPACE
class QQmlType;
+class QQmlEngine;
class QQmlCustomParser;
class QQmlTypePrivate;
class QQmlTypeModule;
@@ -76,6 +77,7 @@ class Q_QML_PRIVATE_EXPORT QQmlMetaType
public:
static QList<QString> qmlTypeNames();
static QList<QQmlType*> qmlTypes();
+ static QList<QQmlType*> qmlSingletonTypes();
static QQmlType *qmlType(const QString &qualifiedName, int, int);
static QQmlType *qmlType(const QHashedStringRef &name, const QHashedStringRef &module, int, int);
@@ -117,30 +119,6 @@ public:
static void setQQuickAnchorLineCompareFunction(CompareFunction);
static bool QQuickAnchorLineCompare(const void *p1, const void *p2);
- struct SingletonInstance {
- SingletonInstance()
- : scriptCallback(0), qobjectCallback(0), qobjectApi(0), instanceMetaObject(0) {}
-
- QJSValue (*scriptCallback)(QQmlEngine *, QJSEngine *);
- QObject *(*qobjectCallback)(QQmlEngine *, QJSEngine *);
- QObject *qobjectApi;
- const QMetaObject *instanceMetaObject;
- QJSValue scriptApi;
-
- };
- struct SingletonType {
- inline SingletonType();
- inline bool operator==(const SingletonType &) const;
- int major;
- int minor;
- QString typeName;
- QObject *(*qobject)(QQmlEngine *, QJSEngine *);
- const QMetaObject *instanceMetaObject;
- QJSValue (*script)(QQmlEngine *, QJSEngine *);
- };
- static SingletonType singletonType(const QString &, int, int);
- static QHash<QString, QList<SingletonType> > singletonTypes();
-
static bool namespaceContainsRegistrations(const QString &);
static void protectNamespace(const QString &);
@@ -154,6 +132,7 @@ private:
static CompareFunction anchorLineCompareFunction;
};
+struct QQmlMetaTypeData;
class QHashedCStringRef;
class QHashedV8String;
class Q_QML_PRIVATE_EXPORT QQmlType
@@ -183,6 +162,7 @@ public:
bool isExtendedType() const;
QString noCreationReason() const;
+ bool isSingleton() const;
bool isInterface() const;
int typeId() const;
int qListTypeId() const;
@@ -203,6 +183,30 @@ public:
int index() const;
+ class Q_QML_PRIVATE_EXPORT SingletonInstanceInfo
+ {
+ public:
+ SingletonInstanceInfo()
+ : scriptCallback(0), qobjectCallback(0), instanceMetaObject(0) {}
+
+ QJSValue (*scriptCallback)(QQmlEngine *, QJSEngine *);
+ QObject *(*qobjectCallback)(QQmlEngine *, QJSEngine *);
+ const QMetaObject *instanceMetaObject;
+ QString typeName;
+
+ void setQObjectApi(QQmlEngine *, QObject *);
+ QObject *qobjectApi(QQmlEngine *) const;
+ void setScriptApi(QQmlEngine *, QJSValue);
+ QJSValue scriptApi(QQmlEngine *) const;
+
+ void init(QQmlEngine *);
+ void destroy(QQmlEngine *);
+
+ QHash<QQmlEngine *, QJSValue> scriptApis;
+ QHash<QQmlEngine *, QObject *> qobjectApis;
+ };
+ SingletonInstanceInfo *singletonInstanceInfo() const;
+
int enumValue(const QHashedStringRef &, bool *ok) const;
int enumValue(const QHashedCStringRef &, bool *ok) const;
int enumValue(const QHashedV8String &, bool *ok) const;
@@ -210,9 +214,19 @@ private:
QQmlType *superType() const;
friend class QQmlTypePrivate;
friend struct QQmlMetaTypeData;
+
+ enum RegistrationType {
+ CppType = 0,
+ SingletonType = 1
+ // In the future, we should register all types via QQmlType, including Composite types.
+ };
+ friend QString registrationTypeString(RegistrationType);
+ friend bool checkRegistration(RegistrationType, QQmlMetaTypeData *, const char *, const QString &);
friend int registerType(const QQmlPrivate::RegisterType &);
+ friend int registerSingletonType(const QQmlPrivate::RegisterSingletonType &);
friend int registerInterface(const QQmlPrivate::RegisterInterface &);
QQmlType(int, const QQmlPrivate::RegisterInterface &);
+ QQmlType(int, const QString &, const QQmlPrivate::RegisterSingletonType &);
QQmlType(int, const QString &, const QQmlPrivate::RegisterType &);
~QQmlType();
@@ -232,10 +246,11 @@ public:
QQmlType *type(const QHashedStringRef &, int);
QQmlType *type(const QHashedV8String &, int);
-private:
- QQmlType *typeNoLock(const QString &name, int minor);
+ QList<QQmlType*> singletonTypes(int) const;
+private:
friend int registerType(const QQmlPrivate::RegisterType &);
+ friend int registerSingletonType(const QQmlPrivate::RegisterSingletonType &);
friend struct QQmlMetaTypeData;
QQmlTypeModule();
@@ -262,25 +277,6 @@ private:
int m_minor;
};
-QQmlMetaType::SingletonType::SingletonType()
-{
- major = 0;
- minor = 0;
- qobject = 0;
- instanceMetaObject = 0;
- script = 0;
-}
-
-bool QQmlMetaType::SingletonType::operator==(const SingletonType &other) const
-{
- return major == other.major && minor == other.minor && script == other.script && qobject == other.qobject;
-}
-
-inline uint qHash(const QQmlMetaType::SingletonType &import)
-{
- return import.major ^ import.minor ^ quintptr(import.script) ^ quintptr(import.qobject);
-}
-
QT_END_NAMESPACE
#endif // QQMLMETATYPE_P_H
diff --git a/src/qml/qml/qqmlprivate.h b/src/qml/qml/qqmlprivate.h
index 7ef24e9f37..aa0ce21ddb 100644
--- a/src/qml/qml/qqmlprivate.h
+++ b/src/qml/qml/qqmlprivate.h
@@ -247,7 +247,10 @@ namespace QQmlPrivate
QJSValue (*scriptApi)(QQmlEngine *, QJSEngine *);
QObject *(*qobjectApi)(QQmlEngine *, QJSEngine *);
- const QMetaObject *instanceMetaObject;
+ const QMetaObject *instanceMetaObject; // new in version 1
+ int typeId; // new in version 2
+ int revision; // new in version 2
+ // If this is extended ensure "version" is bumped!!!
};
enum RegistrationType {
diff --git a/src/qml/qml/qqmltypeloader.cpp b/src/qml/qml/qqmltypeloader.cpp
index 0790b7664e..2f9b2cbb8f 100644
--- a/src/qml/qml/qqmltypeloader.cpp
+++ b/src/qml/qml/qqmltypeloader.cpp
@@ -2295,8 +2295,6 @@ void QQmlScriptBlob::done()
if (isError())
return;
- QQmlEngine *engine = typeLoader()->engine();
-
m_scriptData->importCache = new QQmlTypeNameCache();
QSet<QString> ns;
@@ -2315,7 +2313,7 @@ void QQmlScriptBlob::done()
m_scriptData->importCache->add(script.qualifier, scriptIndex, script.nameSpace);
}
- m_imports.populateCache(m_scriptData->importCache, engine);
+ m_imports.populateCache(m_scriptData->importCache);
m_scriptData->pragmas = m_metadata.pragmas;
m_scriptData->m_programSource = m_source.toUtf8();
diff --git a/src/qml/qml/qqmltypenamecache.cpp b/src/qml/qml/qqmltypenamecache.cpp
index bc75ca6636..e3c142798e 100644
--- a/src/qml/qml/qqmltypenamecache.cpp
+++ b/src/qml/qml/qqmltypenamecache.cpp
@@ -71,21 +71,6 @@ void QQmlTypeNameCache::add(const QHashedString &name, int importedScriptIndex,
m_namedImports.insert(name, import);
}
-void QQmlTypeNameCache::addSingletonType(const QHashedString &name, QQmlMetaType::SingletonInstance *apiInstance, const QHashedString &nameSpace)
-{
- Import import;
- import.singletonType = apiInstance;
-
- if (nameSpace.length() != 0) {
- Import *i = m_namedImports.value(nameSpace);
- Q_ASSERT(i != 0);
- m_namespacedImports[i].insert(name, import);
- } else {
- if (!m_namedImports.contains(name))
- m_namedImports.insert(name, import);
- }
-}
-
QQmlTypeNameCache::Result QQmlTypeNameCache::query(const QHashedStringRef &name)
{
Result result = query(m_namedImports, name);
@@ -132,14 +117,5 @@ QQmlTypeNameCache::Result QQmlTypeNameCache::query(const QHashedV8String &name,
return typeSearch(i->modules, name);
}
-QQmlMetaType::SingletonInstance *QQmlTypeNameCache::singletonType(const void *importNamespace)
-{
- Q_ASSERT(importNamespace);
- const Import *i = static_cast<const Import *>(importNamespace);
- Q_ASSERT(i->scriptIndex == -1);
-
- return i->singletonType;
-}
-
QT_END_NAMESPACE
diff --git a/src/qml/qml/qqmltypenamecache_p.h b/src/qml/qml/qqmltypenamecache_p.h
index 841c5aef6b..3e6afab470 100644
--- a/src/qml/qml/qqmltypenamecache_p.h
+++ b/src/qml/qml/qqmltypenamecache_p.h
@@ -74,7 +74,6 @@ public:
inline bool isEmpty() const;
void add(const QHashedString &name, int sciptIndex = -1, const QHashedString &nameSpace = QHashedString());
- void addSingletonType(const QHashedString &name, QQmlMetaType::SingletonInstance *apiInstance, const QHashedString &nameSpace = QHashedString());
struct Result {
inline Result();
@@ -93,7 +92,6 @@ public:
Result query(const QHashedStringRef &, const void *importNamespace);
Result query(const QHashedV8String &);
Result query(const QHashedV8String &, const void *importNamespace);
- QQmlMetaType::SingletonInstance *singletonType(const void *importNamespace);
private:
friend class QQmlImports;
@@ -101,7 +99,6 @@ private:
struct Import {
inline Import();
// Imported module
- QQmlMetaType::SingletonInstance *singletonType;
QVector<QQmlTypeModuleVersion> modules;
// Or, imported script
@@ -173,7 +170,7 @@ bool QQmlTypeNameCache::Result::isValid() const
}
QQmlTypeNameCache::Import::Import()
-: singletonType(0), scriptIndex(-1)
+: scriptIndex(-1)
{
}
diff --git a/src/qml/qml/v4/qv4bindings.cpp b/src/qml/qml/v4/qv4bindings.cpp
index ddc94d8ce4..7d64de707f 100644
--- a/src/qml/qml/v4/qv4bindings.cpp
+++ b/src/qml/qml/v4/qv4bindings.cpp
@@ -1020,7 +1020,7 @@ void QV4Bindings::run(int instrIndex, quint32 &executedBlocks,
registers[instr->load.reg].setQObject(context->contextObject);
QML_V4_END_INSTR(LoadRoot, load)
- QML_V4_BEGIN_INSTR(LoadModuleObject, load)
+ QML_V4_BEGIN_INSTR(LoadSingletonObject, load)
{
Register &reg = registers[instr->load.reg];
@@ -1028,20 +1028,18 @@ void QV4Bindings::run(int instrIndex, quint32 &executedBlocks,
QQmlTypeNameCache::Result r = context->imports->query(*name);
reg.cleanupString();
- if (r.isValid() && r.importNamespace) {
- QQmlMetaType::SingletonInstance *singletonType = context->imports->singletonType(r.importNamespace);
- if (singletonType) {
- if (singletonType->qobjectCallback) {
- singletonType->qobjectApi = singletonType->qobjectCallback(context->engine, context->engine);
- singletonType->qobjectCallback = 0;
- singletonType->scriptCallback = 0;
- }
- if (singletonType->qobjectApi)
- reg.setQObject(singletonType->qobjectApi);
+ if (r.isValid() && r.type) {
+ if (r.type->isSingleton()) {
+ QQmlEngine *e = context->engine;
+ QQmlType::SingletonInstanceInfo *siinfo = r.type->singletonInstanceInfo();
+ siinfo->init(e); // note: this will also create QJSValue singleton, which is not strictly required here.
+ QObject *qobjectSingleton = siinfo->qobjectApi(e);
+ if (qobjectSingleton)
+ reg.setQObject(qobjectSingleton);
}
}
}
- QML_V4_END_INSTR(LoadModuleObject, load)
+ QML_V4_END_INSTR(LoadSingletonObject, load)
QML_V4_BEGIN_INSTR(LoadAttached, attached)
{
diff --git a/src/qml/qml/v4/qv4compiler.cpp b/src/qml/qml/v4/qv4compiler.cpp
index 1506d09ce9..d5f44c4085 100644
--- a/src/qml/qml/v4/qv4compiler.cpp
+++ b/src/qml/qml/v4/qv4compiler.cpp
@@ -330,18 +330,18 @@ void QV4CompilerPrivate::visitName(IR::Name *e)
gen(attached);
} break;
- case IR::Name::ModuleObject: {
+ case IR::Name::SingletonObject: {
/*
- Existing module object lookup methods include:
- 1. string -> module object (search via importCache->query(name))
- 2. QQmlMetaType::SingletonType -> module object (via QQmlEnginePrivate::singletonTypeInstance() cache)
+ Existing singleton type object lookup methods include:
+ 1. string -> singleton object (search via importCache->query(name))
+ 2. typeid -> singleton object QQmlType (search via ???)
We currently use 1, which is not ideal for performance
*/
_subscribeName << *e->id;
registerLiteralString(currentReg, e->id);
- Instr::LoadModuleObject module;
+ Instr::LoadSingletonObject module;
module.reg = currentReg;
gen(module);
} break;
diff --git a/src/qml/qml/v4/qv4instruction.cpp b/src/qml/qml/v4/qv4instruction.cpp
index 1fbdf3e325..252c9e9a7a 100644
--- a/src/qml/qml/v4/qv4instruction.cpp
+++ b/src/qml/qml/v4/qv4instruction.cpp
@@ -114,8 +114,8 @@ void Bytecode::dump(const V4Instr *i, int address) const
case V4Instr::LoadRoot:
INSTR_DUMP << '\t' << "LoadRoot" << "\t\t" << "-> Output_Reg(" << i->load.reg << ')';
break;
- case V4Instr::LoadModuleObject:
- INSTR_DUMP << '\t' << "LoadModuleObject" << "\t\t" << ") -> Output_Reg(" << i->load.reg << ')';
+ case V4Instr::LoadSingletonObject:
+ INSTR_DUMP << '\t' << "LoadSingletonObject" << "\t\t" << ") -> Output_Reg(" << i->load.reg << ')';
break;
case V4Instr::LoadAttached:
INSTR_DUMP << '\t' << "LoadAttached" << "\t\t" << "Object_Reg(" << i->attached.reg << ") Attached_Index(" << i->attached.id << ") -> Output_Reg(" << i->attached.output << ')';
diff --git a/src/qml/qml/v4/qv4instruction_p.h b/src/qml/qml/v4/qv4instruction_p.h
index 763cd2d67b..34d483b079 100644
--- a/src/qml/qml/v4/qv4instruction_p.h
+++ b/src/qml/qml/v4/qv4instruction_p.h
@@ -73,7 +73,7 @@ QT_BEGIN_NAMESPACE
F(LoadId, load) \
F(LoadScope, load) \
F(LoadRoot, load) \
- F(LoadModuleObject, load) \
+ F(LoadSingletonObject, load) \
F(LoadAttached, attached) \
F(UnaryNot, unaryop) \
F(UnaryMinusNumber, unaryop) \
diff --git a/src/qml/qml/v4/qv4ir.cpp b/src/qml/qml/v4/qv4ir.cpp
index 931a377610..99631cfea6 100644
--- a/src/qml/qml/v4/qv4ir.cpp
+++ b/src/qml/qml/v4/qv4ir.cpp
@@ -551,13 +551,13 @@ Name *BasicBlock::ATTACH_TYPE(const QString &id, const QQmlType *attachType, Nam
return name;
}
-Name *BasicBlock::MODULE_OBJECT(const QString &id, const QQmlMetaObject &meta, Name::Storage storage,
+Name *BasicBlock::SINGLETON_OBJECT(const QString &id, const QQmlMetaObject &meta, Name::Storage storage,
quint16 line, quint16 column)
{
Name *name = function->pool->New<Name>();
name->init(/*base = */ 0, IR::ObjectType,
function->newString(id),
- Name::ModuleObject, line, column);
+ Name::SingletonObject, line, column);
name->meta = meta;
name->storage = storage;
return name;
@@ -700,8 +700,8 @@ static const char *symbolname(Name::Symbol s)
return "IdObject";
case Name::AttachType:
return "AttachType";
- case Name::ModuleObject:
- return "ModuleObject";
+ case Name::SingletonObject:
+ return "SingletonObject";
case Name::Object:
return "Object";
case Name::Property:
diff --git a/src/qml/qml/v4/qv4ir_p.h b/src/qml/qml/v4/qv4ir_p.h
index f6e20a7187..2c31d644e8 100644
--- a/src/qml/qml/v4/qv4ir_p.h
+++ b/src/qml/qml/v4/qv4ir_p.h
@@ -255,12 +255,12 @@ enum BuiltinSymbol {
struct Name: Expr {
enum Symbol {
Unbound,
- IdObject, // This is a load of a id object. Storage will always be IdStorage
- AttachType, // This is a load of an attached object
- ModuleObject, // This is a load of a module object
- Object, // XXX what is this for?
- Property, // This is a load of a regular property
- Slot // XXX what is this for?
+ IdObject, // This is a load of a id object. Storage will always be IdStorage
+ AttachType, // This is a load of an attached object
+ SingletonObject, // This is a load of a singleton object
+ Object, // XXX what is this for?
+ Property, // This is a load of a regular property
+ Slot // XXX what is this for?
};
enum Storage {
@@ -545,7 +545,7 @@ struct BasicBlock {
Name *SYMBOL(Name *base, Type type, const QString &id, const QQmlMetaObject &meta, QQmlPropertyData *property, Name::Storage storage, quint16 line, quint16 column);
Name *ID_OBJECT(const QString &id, const QQmlScript::Object *object, quint16 line, quint16 column);
Name *ATTACH_TYPE(const QString &id, const QQmlType *attachType, Name::Storage storage, quint16 line, quint16 column);
- Name *MODULE_OBJECT(const QString &id, const QQmlMetaObject &meta, Name::Storage storage, quint16 line, quint16 column);
+ Name *SINGLETON_OBJECT(const QString &id, const QQmlMetaObject &meta, Name::Storage storage, quint16 line, quint16 column);
Expr *UNOP(AluOp op, Expr *expr);
Expr *BINOP(AluOp op, Expr *left, Expr *right);
diff --git a/src/qml/qml/v4/qv4irbuilder.cpp b/src/qml/qml/v4/qv4irbuilder.cpp
index 45e3a72986..55381f73a0 100644
--- a/src/qml/qml/v4/qv4irbuilder.cpp
+++ b/src/qml/qml/v4/qv4irbuilder.cpp
@@ -444,20 +444,18 @@ bool QV4IRBuilder::visit(AST::IdentifierExpression *ast)
QQmlTypeNameCache::Result r = m_expression->importCache->query(name);
if (r.isValid()) {
if (r.type) {
- _expr.code = _block->ATTACH_TYPE(name, r.type, IR::Name::ScopeStorage, line, column);
- } else if (r.importNamespace) {
- QQmlMetaType::SingletonInstance *singletonType = m_expression->importCache->singletonType(r.importNamespace);
- if (singletonType && singletonType->instanceMetaObject) {
+ if (r.type->isSingleton()) {
// Note: we don't need to check singletonType->qobjectCallback here, since
// we did that check in registerSingletonType() in qqmlmetatype.cpp.
// We cannot create the QObject Singleton Type Instance here,
// as we might be running in a loader thread.
// Thus, V4 can only handle bindings which use Singleton Types which
// were registered with the templated registration function.
- _expr.code = _block->MODULE_OBJECT(name, singletonType->instanceMetaObject, IR::Name::MemberStorage, line, column);
+ _expr.code = _block->SINGLETON_OBJECT(name, r.type->singletonInstanceInfo()->instanceMetaObject, IR::Name::MemberStorage, line, column);
+ } else {
+ _expr.code = _block->ATTACH_TYPE(name, r.type, IR::Name::ScopeStorage, line, column);
}
}
- // We don't support anything else
} else {
bool found = false;
@@ -625,7 +623,7 @@ bool QV4IRBuilder::visit(AST::FieldMemberExpression *ast)
}
break;
- case IR::Name::ModuleObject: {
+ case IR::Name::SingletonObject: {
if (name.at(0).isUpper()) {
QByteArray utf8Name = name.toUtf8();
const char *enumName = utf8Name.constData();
diff --git a/src/qml/qml/v8/qv8typewrapper.cpp b/src/qml/qml/v8/qv8typewrapper.cpp
index 25695a9fbc..ab077543cd 100644
--- a/src/qml/qml/v8/qv8typewrapper.cpp
+++ b/src/qml/qml/v8/qv8typewrapper.cpp
@@ -134,21 +134,13 @@ QVariant QV8TypeWrapper::toVariant(QV8ObjectResource *r)
QV8TypeResource *resource = static_cast<QV8TypeResource *>(r);
QV8Engine *v8engine = resource->engine;
- if (resource->typeNamespace) {
- if (QQmlMetaType::SingletonInstance *singletonType = resource->typeNamespace->singletonType(resource->importNamespace)) {
- if (singletonType->scriptCallback) {
- singletonType->scriptApi = singletonType->scriptCallback(v8engine->engine(), v8engine->engine());
- singletonType->scriptCallback = 0;
- singletonType->qobjectCallback = 0;
- } else if (singletonType->qobjectCallback) {
- singletonType->qobjectApi = singletonType->qobjectCallback(v8engine->engine(), v8engine->engine());
- singletonType->scriptCallback = 0;
- singletonType->qobjectCallback = 0;
- }
-
- if (singletonType->qobjectApi) {
- return QVariant::fromValue<QObject*>(singletonType->qobjectApi);
- }
+ if (resource->type && resource->type->isSingleton()) {
+ QQmlEngine *e = v8engine->engine();
+ QQmlType::SingletonInstanceInfo *siinfo = resource->type->singletonInstanceInfo();
+ siinfo->init(e); // note: this will also create QJSValue singleton which isn't strictly required.
+ QObject *qobjectSingleton = siinfo->qobjectApi(e);
+ if (qobjectSingleton) {
+ return QVariant::fromValue<QObject*>(qobjectSingleton);
}
}
@@ -174,19 +166,62 @@ v8::Handle<v8::Value> QV8TypeWrapper::Getter(v8::Local<v8::String> property,
if (resource->type) {
QQmlType *type = resource->type;
- if (QV8Engine::startsWithUpper(property)) {
- bool ok = false;
- int value = type->enumValue(propertystring, &ok);
- if (ok)
- return v8::Integer::New(value);
+ // singleton types are handled differently to other types.
+ if (type->isSingleton()) {
+ QQmlEngine *e = v8engine->engine();
+ QQmlType::SingletonInstanceInfo *siinfo = type->singletonInstanceInfo();
+ siinfo->init(e);
+
+ QObject *qobjectSingleton = siinfo->qobjectApi(e);
+ if (qobjectSingleton) {
+ // check for enum value
+ if (QV8Engine::startsWithUpper(property)) {
+ if (resource->mode == IncludeEnums) {
+ QString name = v8engine->toString(property);
+
+ // ### Optimize
+ QByteArray enumName = name.toUtf8();
+ const QMetaObject *metaObject = qobjectSingleton->metaObject();
+ for (int ii = metaObject->enumeratorCount() - 1; ii >= 0; --ii) {
+ QMetaEnum e = metaObject->enumerator(ii);
+ bool ok;
+ int value = e.keyToValue(enumName.constData(), &ok);
+ if (ok)
+ return v8::Integer::New(value);
+ }
+ }
+ }
+
+ // check for property.
+ v8::Handle<v8::Value> rv = v8engine->qobjectWrapper()->getProperty(qobjectSingleton, propertystring, context, QV8QObjectWrapper::IgnoreRevision);
+ return rv;
+ } else if (!siinfo->scriptApi(e).isUndefined()) {
+ // NOTE: if used in a binding, changes will not trigger re-evaluation since non-NOTIFYable.
+ QJSValuePrivate *apiprivate = QJSValuePrivate::get(siinfo->scriptApi(e));
+ QScopedPointer<QJSValuePrivate> propertyValue(apiprivate->property(property).give());
+ return propertyValue->asV8Value(v8engine);
+ }
// Fall through to return empty handle
- } else if (resource->object) {
- QObject *ao = qmlAttachedPropertiesObjectById(type->attachedPropertiesId(), object);
- if (ao)
- return v8engine->qobjectWrapper()->getProperty(ao, propertystring, context,
- QV8QObjectWrapper::IgnoreRevision);
+ } else {
+
+ if (QV8Engine::startsWithUpper(property)) {
+ bool ok = false;
+ int value = type->enumValue(propertystring, &ok);
+ if (ok)
+ return v8::Integer::New(value);
+
+ // Fall through to return empty handle
+
+ } else if (resource->object) {
+ QObject *ao = qmlAttachedPropertiesObjectById(type->attachedPropertiesId(), object);
+ if (ao)
+ return v8engine->qobjectWrapper()->getProperty(ao, propertystring, context,
+ QV8QObjectWrapper::IgnoreRevision);
+
+ // Fall through to return empty handle
+ }
// Fall through to return empty handle
}
@@ -211,49 +246,7 @@ v8::Handle<v8::Value> QV8TypeWrapper::Getter(v8::Local<v8::String> property,
}
return v8::Undefined();
- } else if (QQmlMetaType::SingletonInstance *singletonType = resource->typeNamespace->singletonType(resource->importNamespace)) {
-
- if (singletonType->scriptCallback) {
- singletonType->scriptApi = singletonType->scriptCallback(v8engine->engine(), v8engine->engine());
- singletonType->scriptCallback = 0;
- singletonType->qobjectCallback = 0;
- } else if (singletonType->qobjectCallback) {
- singletonType->qobjectApi = singletonType->qobjectCallback(v8engine->engine(), v8engine->engine());
- singletonType->scriptCallback = 0;
- singletonType->qobjectCallback = 0;
- }
-
- if (singletonType->qobjectApi) {
- // check for enum value
- if (QV8Engine::startsWithUpper(property)) {
- if (resource->mode == IncludeEnums) {
- QString name = v8engine->toString(property);
-
- // ### Optimize
- QByteArray enumName = name.toUtf8();
- const QMetaObject *metaObject = singletonType->qobjectApi->metaObject();
- for (int ii = metaObject->enumeratorCount() - 1; ii >= 0; --ii) {
- QMetaEnum e = metaObject->enumerator(ii);
- bool ok;
- int value = e.keyToValue(enumName.constData(), &ok);
- if (ok)
- return v8::Integer::New(value);
- }
- }
- }
- // check for property.
- v8::Handle<v8::Value> rv = v8engine->qobjectWrapper()->getProperty(singletonType->qobjectApi, propertystring,
- context, QV8QObjectWrapper::IgnoreRevision);
- return rv;
- } else if (!singletonType->scriptApi.isUndefined()) {
- // NOTE: if used in a binding, changes will not trigger re-evaluation since non-NOTIFYable.
- QJSValuePrivate *apiprivate = QJSValuePrivate::get(singletonType->scriptApi);
- QScopedPointer<QJSValuePrivate> propertyValue(apiprivate->property(property).give());
- return propertyValue->asV8Value(v8engine);
- } else {
- return v8::Handle<v8::Value>();
- }
}
// Fall through to return empty handle
@@ -279,38 +272,31 @@ v8::Handle<v8::Value> QV8TypeWrapper::Setter(v8::Local<v8::String> property,
QHashedV8String propertystring(property);
- if (resource->type && resource->object) {
- QQmlType *type = resource->type;
+ QQmlType *type = resource->type;
+ if (type && !type->isSingleton() && resource->object) {
QObject *object = resource->object;
QObject *ao = qmlAttachedPropertiesObjectById(type->attachedPropertiesId(), object);
if (ao)
v8engine->qobjectWrapper()->setProperty(ao, propertystring, context, value,
QV8QObjectWrapper::IgnoreRevision);
- } else if (resource->typeNamespace) {
- if (QQmlMetaType::SingletonInstance *singletonType = resource->typeNamespace->singletonType(resource->importNamespace)) {
- if (singletonType->scriptCallback) {
- singletonType->scriptApi = singletonType->scriptCallback(v8engine->engine(), v8engine->engine());
- singletonType->scriptCallback = 0;
- singletonType->qobjectCallback = 0;
- } else if (singletonType->qobjectCallback) {
- singletonType->qobjectApi = singletonType->qobjectCallback(v8engine->engine(), v8engine->engine());
- singletonType->scriptCallback = 0;
- singletonType->qobjectCallback = 0;
- }
-
- if (singletonType->qobjectApi) {
- v8engine->qobjectWrapper()->setProperty(singletonType->qobjectApi, propertystring, context, value,
- QV8QObjectWrapper::IgnoreRevision);
- } else if (!singletonType->scriptApi.isUndefined()) {
- QScopedPointer<QJSValuePrivate> setvalp(new QJSValuePrivate(v8engine, value));
- QJSValuePrivate *apiprivate = QJSValuePrivate::get(singletonType->scriptApi);
- if (apiprivate->propertyFlags(property) & QJSValuePrivate::ReadOnly) {
- QString error = QLatin1String("Cannot assign to read-only property \"") +
- v8engine->toString(property) + QLatin1Char('\"');
- v8::ThrowException(v8::Exception::Error(v8engine->toString(error)));
- } else {
- apiprivate->setProperty(property, setvalp.data());
- }
+ } else if (type && type->isSingleton()) {
+ QQmlEngine *e = v8engine->engine();
+ QQmlType::SingletonInstanceInfo *siinfo = type->singletonInstanceInfo();
+ siinfo->init(e);
+
+ QObject *qobjectSingleton = siinfo->qobjectApi(e);
+ if (qobjectSingleton) {
+ v8engine->qobjectWrapper()->setProperty(qobjectSingleton, propertystring, context, value,
+ QV8QObjectWrapper::IgnoreRevision);
+ } else if (!siinfo->scriptApi(e).isUndefined()) {
+ QScopedPointer<QJSValuePrivate> setvalp(new QJSValuePrivate(v8engine, value));
+ QJSValuePrivate *apiprivate = QJSValuePrivate::get(siinfo->scriptApi(e));
+ if (apiprivate->propertyFlags(property) & QJSValuePrivate::ReadOnly) {
+ QString error = QLatin1String("Cannot assign to read-only property \"") +
+ v8engine->toString(property) + QLatin1Char('\"');
+ v8::ThrowException(v8::Exception::Error(v8engine->toString(error)));
+ } else {
+ apiprivate->setProperty(property, setvalp.data());
}
}
}