aboutsummaryrefslogtreecommitdiffstats
path: root/src/qml
diff options
context:
space:
mode:
authorLiang Qi <liang.qi@qt.io>2018-02-12 13:26:55 +0100
committerLiang Qi <liang.qi@qt.io>2018-02-12 16:31:13 +0100
commit4d525de33e2ee55e69bb6c90fc11049a0f8b36b5 (patch)
treec9808baeabb1121f488a7b59ffff314cc62d80e8 /src/qml
parent47cd9da96371ccd495f6caabe1c6853258210ebb (diff)
parent3e3c6717ba634825a65069541500c40645a808ee (diff)
Merge remote-tracking branch 'origin/5.10' into 5.11
Conflicts: src/imports/shapes/qquickshape.cpp src/imports/shapes/qquickshape_p_p.h src/qml/compiler/qqmlpropertycachecreator_p.h src/qml/jsruntime/qv4value_p.h src/quick/items/qquickloader_p.h tests/auto/qml/qqmlecmascript/tst_qqmlecmascript.cpp tools/qmlprofiler/qmlprofilerapplication.cpp Change-Id: Iafc66ae84bf78630ed72a986acb678e9d19e3a69
Diffstat (limited to 'src/qml')
-rw-r--r--src/qml/compiler/qqmlirbuilder.cpp3
-rw-r--r--src/qml/compiler/qqmlpropertycachecreator_p.h27
-rw-r--r--src/qml/compiler/qqmltypecompiler.cpp6
-rw-r--r--src/qml/doc/snippets/code/src_script_qjsengine.cpp20
-rw-r--r--src/qml/doc/src/qmlfunctions.qdoc25
-rw-r--r--src/qml/doc/src/qmllanguageref/syntax/basics.qdoc2
-rw-r--r--src/qml/doc/src/qmllanguageref/typesystem/objecttypes.qdoc2
-rw-r--r--src/qml/jsapi/qjsengine.cpp24
-rw-r--r--src/qml/jsruntime/qv4persistent.cpp34
-rw-r--r--src/qml/jsruntime/qv4value_p.h4
-rw-r--r--src/qml/memory/qv4mm.cpp15
-rw-r--r--src/qml/qml/qqmldata_p.h10
-rw-r--r--src/qml/qml/qqmlengine.cpp24
-rw-r--r--src/qml/qml/qqmlimport.cpp150
-rw-r--r--src/qml/qml/qqmlmetatype.cpp9
-rw-r--r--src/qml/qml/qqmlobjectcreator.cpp3
-rw-r--r--src/qml/qml/qqmlobjectcreator_p.h2
-rw-r--r--src/qml/qml/qqmltypewrapper.cpp22
-rw-r--r--src/qml/qml/qqmlvaluetypewrapper.cpp2
19 files changed, 269 insertions, 115 deletions
diff --git a/src/qml/compiler/qqmlirbuilder.cpp b/src/qml/compiler/qqmlirbuilder.cpp
index c95f8ad344..6de0ed6f7d 100644
--- a/src/qml/compiler/qqmlirbuilder.cpp
+++ b/src/qml/compiler/qqmlirbuilder.cpp
@@ -1587,6 +1587,9 @@ QV4::CompiledData::Unit *QmlUnitGenerator::generate(Document &output, const QV4:
QV4::CompiledData::Unit *qmlUnit = reinterpret_cast<QV4::CompiledData::Unit *>(data);
qmlUnit->unitSize = totalSize;
qmlUnit->flags |= QV4::CompiledData::Unit::IsQml;
+ // This unit's memory was allocated with malloc on the heap, so it's
+ // definitely not suitable for StaticData access.
+ qmlUnit->flags &= ~QV4::CompiledData::Unit::StaticData;
qmlUnit->offsetToImports = unitSize;
qmlUnit->nImports = output.imports.count();
qmlUnit->offsetToObjects = unitSize + importSize;
diff --git a/src/qml/compiler/qqmlpropertycachecreator_p.h b/src/qml/compiler/qqmlpropertycachecreator_p.h
index 0a525e418c..7a52f3a12c 100644
--- a/src/qml/compiler/qqmlpropertycachecreator_p.h
+++ b/src/qml/compiler/qqmlpropertycachecreator_p.h
@@ -553,11 +553,11 @@ public:
void appendAliasPropertiesToMetaObjects();
- void appendAliasesToPropertyCache(const CompiledObject &component, int objectIndex);
+ QQmlCompileError appendAliasesToPropertyCache(const CompiledObject &component, int objectIndex);
private:
void appendAliasPropertiesInMetaObjectsWithinComponent(const CompiledObject &component, int firstObjectIndex);
- void propertyDataForAlias(const CompiledObject &component, const QV4::CompiledData::Alias &alias, int *type, int *rev, QQmlPropertyRawData::Flags *propertyFlags);
+ QQmlCompileError propertyDataForAlias(const CompiledObject &component, const QV4::CompiledData::Alias &alias, int *type, int *rev, QQmlPropertyRawData::Flags *propertyFlags);
void collectObjectsWithAliasesRecursively(int objectIndex, QVector<int> *objectsWithAliases) const;
@@ -668,7 +668,7 @@ inline void QQmlPropertyCacheAliasCreator<ObjectContainer>::collectObjectsWithAl
}
template <typename ObjectContainer>
-inline void QQmlPropertyCacheAliasCreator<ObjectContainer>::propertyDataForAlias(
+inline QQmlCompileError QQmlPropertyCacheAliasCreator<ObjectContainer>::propertyDataForAlias(
const CompiledObject &component, const QV4::CompiledData::Alias &alias, int *type, int *minorVersion,
QQmlPropertyData::Flags *propertyFlags)
{
@@ -687,12 +687,16 @@ inline void QQmlPropertyCacheAliasCreator<ObjectContainer>::propertyDataForAlias
auto targetAlias = targetObject.aliasesBegin();
for (uint i = 0; i < alias.localAliasIndex; ++i)
++targetAlias;
- propertyDataForAlias(component, *targetAlias, type, minorVersion, propertyFlags);
- return;
+ return propertyDataForAlias(component, *targetAlias, type, minorVersion, propertyFlags);
} else if (alias.encodedMetaPropertyIndex == -1) {
Q_ASSERT(alias.flags & QV4::CompiledData::Alias::AliasPointsToPointerObject);
auto *typeRef = objectContainer->resolvedTypes.value(targetObject.inheritedTypeNameIndex);
- Q_ASSERT(typeRef);
+ if (!typeRef) {
+ // Can be caused by the alias target not being a valid id or property. E.g.:
+ // property alias dataValue: dataVal
+ // invalidAliasComponent { id: dataVal }
+ return QQmlCompileError(targetObject.location, QQmlPropertyCacheCreatorBase::tr("Invalid alias target"));
+ }
if (typeRef->type.isValid())
*type = typeRef->type.typeId();
@@ -737,15 +741,16 @@ inline void QQmlPropertyCacheAliasCreator<ObjectContainer>::propertyDataForAlias
propertyFlags->isWritable = !(alias.flags & QV4::CompiledData::Property::IsReadOnly) && writable;
propertyFlags->isResettable = resettable;
+ return QQmlCompileError();
}
template <typename ObjectContainer>
-inline void QQmlPropertyCacheAliasCreator<ObjectContainer>::appendAliasesToPropertyCache(
+inline QQmlCompileError QQmlPropertyCacheAliasCreator<ObjectContainer>::appendAliasesToPropertyCache(
const CompiledObject &component, int objectIndex)
{
const CompiledObject &object = *objectContainer->objectAt(objectIndex);
if (!object.aliasCount())
- return;
+ return QQmlCompileError();
QQmlPropertyCache *propertyCache = propertyCaches->at(objectIndex);
Q_ASSERT(propertyCache);
@@ -762,7 +767,9 @@ inline void QQmlPropertyCacheAliasCreator<ObjectContainer>::appendAliasesToPrope
int type = 0;
int minorVersion = 0;
QQmlPropertyData::Flags propertyFlags;
- propertyDataForAlias(component, *alias, &type, &minorVersion, &propertyFlags);
+ QQmlCompileError error = propertyDataForAlias(component, *alias, &type, &minorVersion, &propertyFlags);
+ if (error.isSet())
+ return error;
const QString propertyName = objectContainer->stringAt(alias->nameIndex);
@@ -772,6 +779,8 @@ inline void QQmlPropertyCacheAliasCreator<ObjectContainer>::appendAliasesToPrope
propertyCache->appendProperty(propertyName, propertyFlags, effectivePropertyIndex++,
type, minorVersion, effectiveSignalIndex++);
}
+
+ return QQmlCompileError();
}
template <typename ObjectContainer>
diff --git a/src/qml/compiler/qqmltypecompiler.cpp b/src/qml/compiler/qqmltypecompiler.cpp
index df1f00f2f7..ac373aafb4 100644
--- a/src/qml/compiler/qqmltypecompiler.cpp
+++ b/src/qml/compiler/qqmltypecompiler.cpp
@@ -1023,7 +1023,11 @@ bool QQmlComponentAndAliasResolver::resolveAliases(int componentIndex)
}
if (result == AllAliasesResolved) {
- aliasCacheCreator.appendAliasesToPropertyCache(*qmlObjects->at(componentIndex), objectIndex);
+ QQmlCompileError error = aliasCacheCreator.appendAliasesToPropertyCache(*qmlObjects->at(componentIndex), objectIndex);
+ if (error.isSet()) {
+ recordError(error);
+ return false;
+ }
atLeastOneAliasResolved = true;
} else if (result == SomeAliasesResolved) {
atLeastOneAliasResolved = true;
diff --git a/src/qml/doc/snippets/code/src_script_qjsengine.cpp b/src/qml/doc/snippets/code/src_script_qjsengine.cpp
index 3799189f83..6c58fd8a18 100644
--- a/src/qml/doc/snippets/code/src_script_qjsengine.cpp
+++ b/src/qml/doc/snippets/code/src_script_qjsengine.cpp
@@ -114,3 +114,23 @@ engine.globalObject().setProperty("myObject", myScriptQObject);
qDebug() << engine.evaluate("myObject.dynamicProperty").toInt();
//! [6]
+
+
+//! [7]
+class MyObject : public QObject
+{
+ Q_OBJECT
+
+public:
+ Q_INVOKABLE MyObject() {}
+};
+//! [7]
+
+//! [8]
+QJSValue jsMetaObject = engine.newQMetaObject(&MyObject::staticMetaObject);
+engine.globalObject().setProperty("MyObject", jsMetaObject);
+//! [8]
+
+//! [9]
+engine.evaluate("var myObject = new MyObject()");
+//! [9]
diff --git a/src/qml/doc/src/qmlfunctions.qdoc b/src/qml/doc/src/qmlfunctions.qdoc
index 8a62a18eec..f939ddbcf3 100644
--- a/src/qml/doc/src/qmlfunctions.qdoc
+++ b/src/qml/doc/src/qmlfunctions.qdoc
@@ -324,6 +324,19 @@
qmlRegisterSingletonType("Qt.example.qjsvalueApi", 1, 0, "MyApi", example_qjsvalue_singletontype_provider);
\endcode
+ Alternatively, you can use a C++11 lambda:
+
+ \code
+ qmlRegisterSingletonType("Qt.example.qjsvalueApi", 1, 0, "MyApi", [](QQmlEngine *engine, QJSEngine *scriptEngine) -> QJSValue {
+ Q_UNUSED(engine)
+
+ static int seedValue = 5;
+ QJSValue example = scriptEngine->newObject();
+ example.setProperty("someProperty", seedValue++);
+ return example;
+ });
+ \endcode
+
In order to use the registered singleton type in QML, you must import the singleton type.
\qml
import QtQuick 2.0
@@ -423,6 +436,18 @@
qmlRegisterSingletonType<SingletonTypeExample>("Qt.example.qobjectSingleton", 1, 0, "MyApi", example_qobject_singletontype_provider);
\endcode
+ Alternatively, you can use a C++11 lambda:
+
+ \code
+ qmlRegisterSingletonType<SingletonTypeExample>("Qt.example.qjsvalueApi", 1, 0, "MyApi", [](QQmlEngine *engine, QJSEngine *scriptEngine) -> QObject * {
+ Q_UNUSED(engine)
+ Q_UNUSED(scriptEngine)
+
+ SingletonTypeExample *example = new SingletonTypeExample();
+ return example;
+ });
+ \endcode
+
In order to use the registered singleton type in QML, you must import the singleton type.
\qml
import QtQuick 2.0
diff --git a/src/qml/doc/src/qmllanguageref/syntax/basics.qdoc b/src/qml/doc/src/qmllanguageref/syntax/basics.qdoc
index 1b645a94c0..9eb8f72cf2 100644
--- a/src/qml/doc/src/qmllanguageref/syntax/basics.qdoc
+++ b/src/qml/doc/src/qmllanguageref/syntax/basics.qdoc
@@ -38,6 +38,8 @@ imperative code, in the case where complex custom application behavior is needed
QML source code is generally loaded by the engine through QML \e documents, which are
standalone documents of QML code. These can be used to define \l {QML Object Types}{QML object types} that can then be reused throughout an application.
+Note that type names must begin with an uppercase letter in order
+to be declared as QML object types in a QML file.
\section1 Import Statements
diff --git a/src/qml/doc/src/qmllanguageref/typesystem/objecttypes.qdoc b/src/qml/doc/src/qmllanguageref/typesystem/objecttypes.qdoc
index b74646b7d0..5f089b5ebc 100644
--- a/src/qml/doc/src/qmllanguageref/typesystem/objecttypes.qdoc
+++ b/src/qml/doc/src/qmllanguageref/typesystem/objecttypes.qdoc
@@ -45,6 +45,8 @@ type, as discussed in \l {qtqml-documents-definetypes.html}
{Documents as QML object type definitions}, or by defining a QML type from C++
and registering the type with the QML engine, as discussed in
\l{qtqml-cppintegration-definetypes.html}{Defining QML Types from C++}.
+Note that in both cases, the type name must begin with an uppercase letter in
+order to be declared as a QML object type in a QML file.
\section1 Defining Object Types from QML
diff --git a/src/qml/jsapi/qjsengine.cpp b/src/qml/jsapi/qjsengine.cpp
index d83d9c7927..1c1314f05d 100644
--- a/src/qml/jsapi/qjsengine.cpp
+++ b/src/qml/jsapi/qjsengine.cpp
@@ -166,16 +166,30 @@ Q_DECLARE_METATYPE(QList<int>)
properties of the proxy object. No binding code is needed because it
is done dynamically using the Qt meta object system.
+ \snippet code/src_script_qjsengine.cpp 5
+
Use newQMetaObject() to wrap a QMetaObject; this gives you a
"script representation" of a QObject-based class. newQMetaObject()
returns a proxy script object; enum values of the class are available
as properties of the proxy object.
- Constructors exposed to the meta-object system ( using Q_INVOKABLE ) can be
+ Constructors exposed to the meta-object system (using Q_INVOKABLE) can be
called from the script to create a new QObject instance with
- JavaScriptOwnership.
+ JavaScriptOwnership. For example, given the following class definition:
- \snippet code/src_script_qjsengine.cpp 5
+ \snippet code/src_script_qjsengine.cpp 7
+
+ The \c staticMetaObject for the class can be exposed to JavaScript like so:
+
+ \snippet code/src_script_qjsengine.cpp 8
+
+ Instances of the class can then be created in JavaScript:
+
+ \snippet code/src_script_qjsengine.cpp 9
+
+ \note Currently only classes using the Q_OBJECT macro are supported; it is
+ not possible to expose the \c staticMetaObject of a Q_GADGET class to
+ JavaScript.
\section2 Dynamic QObject Properties
@@ -541,7 +555,7 @@ QJSValue QJSEngine::newQObject(QObject *object)
When called as a constructor, a new instance of the class will be created.
Only constructors exposed by Q_INVOKABLE will be visible from the script engine.
- \sa newQObject()
+ \sa newQObject(), {QObject Integration}
*/
QJSValue QJSEngine::newQMetaObject(const QMetaObject* metaObject) {
@@ -558,7 +572,7 @@ QJSValue QJSEngine::newQMetaObject(const QMetaObject* metaObject) {
Creates a JavaScript object that wraps the static QMetaObject associated
with class \c{T}.
- \sa newQObject()
+ \sa newQObject(), {QObject Integration}
*/
diff --git a/src/qml/jsruntime/qv4persistent.cpp b/src/qml/jsruntime/qv4persistent.cpp
index 0b31c971f9..973541553a 100644
--- a/src/qml/jsruntime/qv4persistent.cpp
+++ b/src/qml/jsruntime/qv4persistent.cpp
@@ -68,6 +68,22 @@ Page *getPage(Value *val) {
return reinterpret_cast<Page *>(reinterpret_cast<quintptr>(val) & ~((quintptr)(WTF::pageSize() - 1)));
}
+QML_NEARLY_ALWAYS_INLINE void insertInFront(PersistentValueStorage *storage, Page *p)
+{
+ p->header.next = reinterpret_cast<Page *>(storage->firstPage);
+ p->header.prev = reinterpret_cast<Page **>(&storage->firstPage);
+ if (p->header.next)
+ p->header.next->header.prev = &p->header.next;
+ storage->firstPage = p;
+}
+
+QML_NEARLY_ALWAYS_INLINE void unlink(Page *p)
+{
+ if (p->header.prev)
+ *p->header.prev = p->header.next;
+ if (p->header.next)
+ p->header.next->header.prev = p->header.prev;
+}
Page *allocatePage(PersistentValueStorage *storage)
{
@@ -78,19 +94,14 @@ Page *allocatePage(PersistentValueStorage *storage)
p->header.engine = storage->engine;
p->header.alloc = page;
- p->header.next = reinterpret_cast<Page *>(storage->firstPage);
- p->header.prev = reinterpret_cast<Page **>(&storage->firstPage);
p->header.refCount = 0;
p->header.freeList = 0;
- if (p->header.next)
- p->header.next->header.prev = &p->header.next;
+ insertInFront(storage, p);
for (int i = 0; i < kEntriesPerPage - 1; ++i) {
p->values[i].setEmpty(i + 1);
}
p->values[kEntriesPerPage - 1].setEmpty(-1);
- storage->firstPage = p;
-
return p;
}
@@ -195,6 +206,12 @@ Value *PersistentValueStorage::allocate()
Value *v = p->values + p->header.freeList;
p->header.freeList = v->int_32();
+
+ if (p->header.freeList != -1 && p != firstPage) {
+ unlink(p);
+ insertInFront(this, p);
+ }
+
++p->header.refCount;
v->setRawValue(Encode::undefined());
@@ -237,10 +254,7 @@ ExecutionEngine *PersistentValueStorage::getEngine(Value *v)
void PersistentValueStorage::freePage(void *page)
{
Page *p = static_cast<Page *>(page);
- if (p->header.prev)
- *p->header.prev = p->header.next;
- if (p->header.next)
- p->header.next->header.prev = p->header.prev;
+ unlink(p);
p->header.alloc.deallocate();
}
diff --git a/src/qml/jsruntime/qv4value_p.h b/src/qml/jsruntime/qv4value_p.h
index 843fbc1d91..b3f04d69be 100644
--- a/src/qml/jsruntime/qv4value_p.h
+++ b/src/qml/jsruntime/qv4value_p.h
@@ -57,6 +57,8 @@
#include "qv4global_p.h"
#include <private/qv4heap_p.h>
+#include <private/qnumeric_p.h>
+
QT_BEGIN_NAMESPACE
namespace QV4 {
@@ -322,6 +324,8 @@ public:
return d;
}
QML_NEARLY_ALWAYS_INLINE void setDouble(double d) {
+ if (qt_is_nan(d))
+ d = qt_qnan();
memcpy(&_val, &d, 8);
_val ^= NaNEncodeMask;
Q_ASSERT(isDouble());
diff --git a/src/qml/memory/qv4mm.cpp b/src/qml/memory/qv4mm.cpp
index 4a0c12b9da..9c51013317 100644
--- a/src/qml/memory/qv4mm.cpp
+++ b/src/qml/memory/qv4mm.cpp
@@ -342,6 +342,9 @@ bool Chunk::sweep(ExecutionEngine *engine)
v->destroy(b);
b->_checkIsDestroyed();
}
+#ifdef V4_USE_HEAPTRACK
+ heaptrack_report_free(itemToFree);
+#endif
}
Q_V4_PROFILE_DEALLOC(engine, qPopulationCount((objectBitmap[i] | extendsBitmap[i])
- (blackBitmap[i] | e)) * Chunk::SlotSize,
@@ -390,6 +393,9 @@ void Chunk::freeAll(ExecutionEngine *engine)
b->vtable()->destroy(b);
b->_checkIsDestroyed();
}
+#ifdef V4_USE_HEAPTRACK
+ heaptrack_report_free(itemToFree);
+#endif
}
Q_V4_PROFILE_DEALLOC(engine, (qPopulationCount(objectBitmap[i]|extendsBitmap[i])
- qPopulationCount(e)) * Chunk::SlotSize, Profiling::SmallItem);
@@ -602,6 +608,9 @@ HeapItem *BlockAllocator::allocate(size_t size, bool forceAllocation) {
done:
m->setAllocatedSlots(slotsRequired);
Q_V4_PROFILE_ALLOC(engine, slotsRequired * Chunk::SlotSize, Profiling::SmallItem);
+#ifdef V4_USE_HEAPTRACK
+ heaptrack_report_alloc(m, slotsRequired * Chunk::SlotSize);
+#endif
// DEBUG << " " << hex << m->chunk() << m->chunk()->objectBitmap[0] << m->chunk()->extendsBitmap[0] << (m - m->chunk()->realBase());
return m;
}
@@ -659,6 +668,9 @@ HeapItem *HugeItemAllocator::allocate(size_t size) {
chunks.push_back(HugeChunk{c, size});
Chunk::setBit(c->objectBitmap, c->first() - c->realBase());
Q_V4_PROFILE_ALLOC(engine, size, Profiling::LargeItem);
+#ifdef V4_USE_HEAPTRACK
+ heaptrack_report_alloc(c, size);
+#endif
return c->first();
}
@@ -675,6 +687,9 @@ static void freeHugeChunk(ChunkAllocator *chunkAllocator, const HugeItemAllocato
b->_checkIsDestroyed();
}
chunkAllocator->free(c.chunk, c.size);
+#ifdef V4_USE_HEAPTRACK
+ heaptrack_report_free(c.chunk);
+#endif
}
void HugeItemAllocator::sweep(ClassDestroyStatsCallback classCountPtr)
diff --git a/src/qml/qml/qqmldata_p.h b/src/qml/qml/qqmldata_p.h
index 5794e6f0c5..17d145f939 100644
--- a/src/qml/qml/qqmldata_p.h
+++ b/src/qml/qml/qqmldata_p.h
@@ -56,6 +56,7 @@
#include <private/qqmlpropertyindex_p.h>
#include <private/qv4value_p.h>
#include <private/qv4persistent_p.h>
+#include <private/qqmlrefcount_p.h>
#include <qjsengine.h>
#include <qvector.h>
@@ -116,6 +117,7 @@ class Q_QML_PRIVATE_EXPORT QQmlData : public QAbstractDeclarativeData
{
public:
QQmlData();
+ ~QQmlData();
static inline void init() {
static bool initialized = false;
@@ -219,12 +221,15 @@ public:
quint32 jsEngineId; // id of the engine that created the jsWrapper
struct DeferredData {
+ DeferredData();
+ ~DeferredData();
unsigned int deferredIdx;
QMultiHash<int, const QV4::CompiledData::Binding *> bindings;
- QV4::CompiledData::CompilationUnit *compilationUnit;//Not always the same as the other compilation unit
+ QQmlRefPointer<QV4::CompiledData::CompilationUnit> compilationUnit;//Not always the same as the other compilation unit
QQmlContextData *context;//Could be either context or outerContext
+ Q_DISABLE_COPY(DeferredData);
};
- QV4::CompiledData::CompilationUnit *compilationUnit;
+ QQmlRefPointer<QV4::CompiledData::CompilationUnit> compilationUnit;
QVector<DeferredData *> deferredData;
void deferData(int objectIndex, QV4::CompiledData::CompilationUnit *, QQmlContextData *);
@@ -299,6 +304,7 @@ private:
const BindingBitsType *bits = (bindingBitsArraySize == InlineBindingArraySize) ? bindingBitsValue : bindingBits;
return bits[offset] & bitFlagForBit(bit);
}
+ Q_DISABLE_COPY(QQmlData);
};
bool QQmlData::wasDeleted(const QObject *object)
diff --git a/src/qml/qml/qqmlengine.cpp b/src/qml/qml/qqmlengine.cpp
index 80ec44e1e4..02e206284b 100644
--- a/src/qml/qml/qqmlengine.cpp
+++ b/src/qml/qml/qqmlengine.cpp
@@ -752,13 +752,17 @@ QQmlData::QQmlData()
hasInterceptorMetaObject(false), hasVMEMetaObject(false), parentFrozen(false),
bindingBitsArraySize(InlineBindingArraySize), notifyList(0),
bindings(0), signalHandlers(0), nextContextObject(0), prevContextObject(0),
- lineNumber(0), columnNumber(0), jsEngineId(0), compilationUnit(0),
+ lineNumber(0), columnNumber(0), jsEngineId(0),
propertyCache(0), guards(0), extendedData(0)
{
memset(bindingBitsValue, 0, sizeof(bindingBitsValue));
init();
}
+QQmlData::~QQmlData()
+{
+}
+
void QQmlData::destroyed(QAbstractDeclarativeData *d, QObject *o)
{
QQmlData *ddata = static_cast<QQmlData *>(d);
@@ -930,6 +934,14 @@ void QQmlData::flushPendingBindingImpl(QQmlPropertyIndex index)
QQmlPropertyData::DontRemoveBinding);
}
+QQmlData::DeferredData::DeferredData()
+{
+}
+
+QQmlData::DeferredData::~DeferredData()
+{
+}
+
bool QQmlEnginePrivate::baseModulesUninitialized = true;
void QQmlEnginePrivate::init()
{
@@ -1684,7 +1696,6 @@ void QQmlData::deferData(int objectIndex, QV4::CompiledData::CompilationUnit *co
QQmlData::DeferredData *deferData = new QQmlData::DeferredData;
deferData->deferredIdx = objectIndex;
deferData->compilationUnit = compilationUnit;
- deferData->compilationUnit->addref();
deferData->context = context;
const QV4::CompiledData::Object *compiledObject = compilationUnit->objectAt(objectIndex);
@@ -1706,7 +1717,6 @@ void QQmlData::releaseDeferredData()
while (it != deferredData.end()) {
DeferredData *deferData = *it;
if (deferData->bindings.isEmpty()) {
- deferData->compilationUnit->release();
delete deferData;
it = deferredData.erase(it);
} else {
@@ -1784,12 +1794,10 @@ void QQmlData::destroyed(QObject *object)
if (bindings && !bindings->ref.deref())
delete bindings;
- if (compilationUnit) {
- compilationUnit->release();
- compilationUnit = 0;
- }
+ compilationUnit = nullptr;
- releaseDeferredData();
+ qDeleteAll(deferredData);
+ deferredData.clear();
QQmlBoundSignal *signalHandler = signalHandlers;
while (signalHandler) {
diff --git a/src/qml/qml/qqmlimport.cpp b/src/qml/qml/qqmlimport.cpp
index f2757c34be..a9113603b8 100644
--- a/src/qml/qml/qqmlimport.cpp
+++ b/src/qml/qml/qqmlimport.cpp
@@ -2080,29 +2080,38 @@ bool QQmlImportDatabase::importStaticPlugin(QObject *instance, const QString &ba
// Dynamic plugins are differentiated by their filepath. For static plugins we
// don't have that information so we use their address as key instead.
const QString uniquePluginID = QString::asprintf("%p", instance);
- StringRegisteredPluginMap *plugins = qmlEnginePluginsWithRegisteredTypes();
- QMutexLocker lock(&plugins->mutex);
+ {
+ StringRegisteredPluginMap *plugins = qmlEnginePluginsWithRegisteredTypes();
+ QMutexLocker lock(&plugins->mutex);
- // Plugin types are global across all engines and should only be
- // registered once. But each engine still needs to be initialized.
- bool typesRegistered = plugins->contains(uniquePluginID);
- bool engineInitialized = initializedPlugins.contains(uniquePluginID);
+ // Plugin types are global across all engines and should only be
+ // registered once. But each engine still needs to be initialized.
+ bool typesRegistered = plugins->contains(uniquePluginID);
- if (typesRegistered) {
- Q_ASSERT_X(plugins->value(uniquePluginID).uri == uri,
- "QQmlImportDatabase::importStaticPlugin",
- "Internal error: Static plugin imported previously with different uri");
- } else {
- RegisteredPlugin plugin;
- plugin.uri = uri;
- plugin.loader = 0;
- plugins->insert(uniquePluginID, plugin);
+ if (typesRegistered) {
+ Q_ASSERT_X(plugins->value(uniquePluginID).uri == uri,
+ "QQmlImportDatabase::importStaticPlugin",
+ "Internal error: Static plugin imported previously with different uri");
+ } else {
+ RegisteredPlugin plugin;
+ plugin.uri = uri;
+ plugin.loader = 0;
+ plugins->insert(uniquePluginID, plugin);
- if (!registerPluginTypes(instance, basePath, uri, typeNamespace, vmaj, errors))
- return false;
+ if (!registerPluginTypes(instance, basePath, uri, typeNamespace, vmaj, errors))
+ return false;
+ }
+
+ // Release the lock on plugins early as we're done with the global part. Releasing the lock
+ // also allows other QML loader threads to acquire the lock while this thread is blocking
+ // in the initializeEngine call to the gui thread (which in turn may be busy waiting for
+ // other QML loader threads and thus not process the initializeEngine call).
}
- if (!engineInitialized) {
+ // The plugin's per-engine initialization does not need lock protection, as this function is
+ // only called from the engine specific loader thread and importDynamicPlugin as well as
+ // importStaticPlugin are the only places of access.
+ if (!initializedPlugins.contains(uniquePluginID)) {
initializedPlugins.insert(uniquePluginID);
if (QQmlExtensionInterface *eiface = qobject_cast<QQmlExtensionInterface *>(instance)) {
@@ -2124,68 +2133,77 @@ bool QQmlImportDatabase::importDynamicPlugin(const QString &filePath, const QStr
QFileInfo fileInfo(filePath);
const QString absoluteFilePath = fileInfo.absoluteFilePath();
+ QObject *instance = nullptr;
bool engineInitialized = initializedPlugins.contains(absoluteFilePath);
- StringRegisteredPluginMap *plugins = qmlEnginePluginsWithRegisteredTypes();
- QMutexLocker lock(&plugins->mutex);
- bool typesRegistered = plugins->contains(absoluteFilePath);
-
- if (typesRegistered) {
- Q_ASSERT_X(plugins->value(absoluteFilePath).uri == uri,
- "QQmlImportDatabase::importDynamicPlugin",
- "Internal error: Plugin imported previously with different uri");
- }
-
- if (!engineInitialized || !typesRegistered) {
- if (!QQml_isFileCaseCorrect(absoluteFilePath)) {
- if (errors) {
- QQmlError error;
- error.setDescription(tr("File name case mismatch for \"%1\"").arg(absoluteFilePath));
- errors->prepend(error);
- }
- return false;
+ {
+ StringRegisteredPluginMap *plugins = qmlEnginePluginsWithRegisteredTypes();
+ QMutexLocker lock(&plugins->mutex);
+ bool typesRegistered = plugins->contains(absoluteFilePath);
+
+ if (typesRegistered) {
+ Q_ASSERT_X(plugins->value(absoluteFilePath).uri == uri,
+ "QQmlImportDatabase::importDynamicPlugin",
+ "Internal error: Plugin imported previously with different uri");
}
- QPluginLoader* loader = 0;
- if (!typesRegistered) {
- loader = new QPluginLoader(absoluteFilePath);
-
- if (!loader->load()) {
+ if (!engineInitialized || !typesRegistered) {
+ if (!QQml_isFileCaseCorrect(absoluteFilePath)) {
if (errors) {
QQmlError error;
- error.setDescription(loader->errorString());
+ error.setDescription(tr("File name case mismatch for \"%1\"").arg(absoluteFilePath));
errors->prepend(error);
}
- delete loader;
return false;
}
- } else {
- loader = plugins->value(absoluteFilePath).loader;
- }
- QObject *instance = loader->instance();
+ QPluginLoader* loader = 0;
+ if (!typesRegistered) {
+ loader = new QPluginLoader(absoluteFilePath);
- if (!typesRegistered) {
- RegisteredPlugin plugin;
- plugin.uri = uri;
- plugin.loader = loader;
- plugins->insert(absoluteFilePath, plugin);
+ if (!loader->load()) {
+ if (errors) {
+ QQmlError error;
+ error.setDescription(loader->errorString());
+ errors->prepend(error);
+ }
+ delete loader;
+ return false;
+ }
+ } else {
+ loader = plugins->value(absoluteFilePath).loader;
+ }
- // Continue with shared code path for dynamic and static plugins:
- if (!registerPluginTypes(instance, fileInfo.absolutePath(), uri, typeNamespace, vmaj, errors))
- return false;
+ instance = loader->instance();
+
+ if (!typesRegistered) {
+ RegisteredPlugin plugin;
+ plugin.uri = uri;
+ plugin.loader = loader;
+ plugins->insert(absoluteFilePath, plugin);
+
+ // Continue with shared code path for dynamic and static plugins:
+ if (!registerPluginTypes(instance, fileInfo.absolutePath(), uri, typeNamespace, vmaj, errors))
+ return false;
+ }
}
- if (!engineInitialized) {
- // things on the engine (eg. adding new global objects) have to be done for every
- // engine.
- // XXX protect against double initialization
- initializedPlugins.insert(absoluteFilePath);
-
- if (QQmlExtensionInterface *eiface = qobject_cast<QQmlExtensionInterface *>(instance)) {
- QQmlEnginePrivate *ep = QQmlEnginePrivate::get(engine);
- ep->typeLoader.initializeEngine(eiface, uri.toUtf8().constData());
- }
- }
+ // Release the lock on plugins early as we're done with the global part. Releasing the lock
+ // also allows other QML loader threads to acquire the lock while this thread is blocking
+ // in the initializeEngine call to the gui thread (which in turn may be busy waiting for
+ // other QML loader threads and thus not process the initializeEngine call).
+ }
+
+
+ if (!engineInitialized) {
+ // The plugin's per-engine initialization does not need lock protection, as this function is
+ // only called from the engine specific loader thread and importDynamicPlugin as well as
+ // importStaticPlugin are the only places of access.
+ initializedPlugins.insert(absoluteFilePath);
+
+ if (QQmlExtensionInterface *eiface = qobject_cast<QQmlExtensionInterface *>(instance)) {
+ QQmlEnginePrivate *ep = QQmlEnginePrivate::get(engine);
+ ep->typeLoader.initializeEngine(eiface, uri.toUtf8().constData());
+ }
}
return true;
diff --git a/src/qml/qml/qqmlmetatype.cpp b/src/qml/qml/qqmlmetatype.cpp
index b324386bf5..76d40bf442 100644
--- a/src/qml/qml/qqmlmetatype.cpp
+++ b/src/qml/qml/qqmlmetatype.cpp
@@ -1566,6 +1566,12 @@ QString registrationTypeString(QQmlType::RegistrationType typeType)
bool checkRegistration(QQmlType::RegistrationType typeType, QQmlMetaTypeData *data, const char *uri, const QString &typeName, int majorVersion = -1)
{
if (!typeName.isEmpty()) {
+ if (typeName.at(0).isLower()) {
+ QString failure(QCoreApplication::translate("qmlRegisterType", "Invalid QML %1 name \"%2\"; type names must begin with an uppercase letter"));
+ data->typeRegistrationFailures.append(failure.arg(registrationTypeString(typeType)).arg(typeName));
+ return false;
+ }
+
int typeNameLen = typeName.length();
for (int ii = 0; ii < typeNameLen; ++ii) {
if (!(typeName.at(ii).isLetterOrNumber() || typeName.at(ii) == '_')) {
@@ -1803,6 +1809,9 @@ int QQmlPrivate::qmlregister(RegistrationType type, void *data)
else
return -1;
+ if (!dtype.isValid())
+ return -1;
+
QMutexLocker lock(metaTypeDataLock());
QQmlMetaTypeData *typeData = metaTypeData();
typeData->undeletableTypes.insert(dtype);
diff --git a/src/qml/qml/qqmlobjectcreator.cpp b/src/qml/qml/qqmlobjectcreator.cpp
index f9aba69986..caf063c79f 100644
--- a/src/qml/qml/qqmlobjectcreator.cpp
+++ b/src/qml/qml/qqmlobjectcreator.cpp
@@ -203,10 +203,7 @@ QObject *QQmlObjectCreator::create(int subComponentIndex, QObject *parent, QQmlI
if (instance) {
QQmlData *ddata = QQmlData::get(instance);
Q_ASSERT(ddata);
- if (ddata->compilationUnit)
- ddata->compilationUnit->release();
ddata->compilationUnit = compilationUnit;
- ddata->compilationUnit->addref();
}
if (topLevelCreator)
diff --git a/src/qml/qml/qqmlobjectcreator_p.h b/src/qml/qml/qqmlobjectcreator_p.h
index f4c03af5b7..bef58b8c9a 100644
--- a/src/qml/qml/qqmlobjectcreator_p.h
+++ b/src/qml/qml/qqmlobjectcreator_p.h
@@ -137,7 +137,7 @@ private:
QQmlEngine *engine;
QV4::ExecutionEngine *v4;
- QV4::CompiledData::CompilationUnit *compilationUnit;
+ QQmlRefPointer<QV4::CompiledData::CompilationUnit> compilationUnit;
const QV4::CompiledData::Unit *qmlUnit;
QQmlGuardedContextData parentContext;
QQmlContextData *context;
diff --git a/src/qml/qml/qqmltypewrapper.cpp b/src/qml/qml/qqmltypewrapper.cpp
index 404bc0612e..8e067932bb 100644
--- a/src/qml/qml/qqmltypewrapper.cpp
+++ b/src/qml/qml/qqmltypewrapper.cpp
@@ -134,11 +134,11 @@ ReturnedValue QQmlTypeWrapper::create(QV4::ExecutionEngine *engine, QObject *o,
}
static int enumForSingleton(QV4::ExecutionEngine *v4, String *name, QObject *qobjectSingleton,
- const QQmlType &type)
+ const QQmlType &type, bool *ok)
{
- bool ok;
- int value = type.enumValue(QQmlEnginePrivate::get(v4->qmlEngine()), name, &ok);
- if (ok)
+ Q_ASSERT(ok != nullptr);
+ int value = type.enumValue(QQmlEnginePrivate::get(v4->qmlEngine()), name, ok);
+ if (*ok)
return value;
// ### Optimize
@@ -146,10 +146,11 @@ static int enumForSingleton(QV4::ExecutionEngine *v4, String *name, QObject *qob
const QMetaObject *metaObject = qobjectSingleton->metaObject();
for (int ii = metaObject->enumeratorCount() - 1; ii >= 0; --ii) {
QMetaEnum e = metaObject->enumerator(ii);
- value = e.keyToValue(enumName.constData(), &ok);
- if (ok)
+ value = e.keyToValue(enumName.constData(), ok);
+ if (*ok)
return value;
}
+ *ok = false;
return -1;
}
@@ -192,8 +193,9 @@ ReturnedValue QQmlTypeWrapper::get(const Managed *m, String *name, bool *hasProp
// check for enum value
const bool includeEnums = w->d()->mode == Heap::QQmlTypeWrapper::IncludeEnums;
if (includeEnums && name->startsWithUpper()) {
- const int value = enumForSingleton(v4, name, qobjectSingleton, type);
- if (value != -1)
+ bool ok = false;
+ const int value = enumForSingleton(v4, name, qobjectSingleton, type, &ok);
+ if (ok)
return QV4::Primitive::fromInt32(value).asReturnedValue();
}
@@ -205,8 +207,8 @@ ReturnedValue QQmlTypeWrapper::get(const Managed *m, String *name, bool *hasProp
// Warn when attempting to access a lowercased enum value, singleton case
if (!ok && includeEnums && !name->startsWithUpper()) {
- const int value = enumForSingleton(v4, name, qobjectSingleton, type);
- if (value != -1)
+ enumForSingleton(v4, name, qobjectSingleton, type, &ok);
+ if (ok)
return throwLowercaseEnumError(v4, name, type);
}
diff --git a/src/qml/qml/qqmlvaluetypewrapper.cpp b/src/qml/qml/qqmlvaluetypewrapper.cpp
index d37065ce43..c643beeadc 100644
--- a/src/qml/qml/qqmlvaluetypewrapper.cpp
+++ b/src/qml/qml/qqmlvaluetypewrapper.cpp
@@ -98,6 +98,8 @@ void Heap::QQmlValueTypeWrapper::destroy()
valueType->metaType.destruct(gadgetPtr);
::operator delete(gadgetPtr);
}
+ if (_propertyCache)
+ _propertyCache->release();
Object::destroy();
}