1 /****************************************************************************
3 ** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
4 ** Contact: http://www.qt-project.org/
6 ** This file is part of the QtQml module of the Qt Toolkit.
8 ** $QT_BEGIN_LICENSE:LGPL$
9 ** GNU Lesser General Public License Usage
10 ** This file may be used under the terms of the GNU Lesser General Public
11 ** License version 2.1 as published by the Free Software Foundation and
12 ** appearing in the file LICENSE.LGPL included in the packaging of this
13 ** file. Please review the following information to ensure the GNU Lesser
14 ** General Public License version 2.1 requirements will be met:
15 ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
17 ** In addition, as a special exception, Nokia gives you certain additional
18 ** rights. These rights are described in the Nokia Qt LGPL Exception
19 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
21 ** GNU General Public License Usage
22 ** Alternatively, this file may be used under the terms of the GNU General
23 ** Public License version 3.0 as published by the Free Software Foundation
24 ** and appearing in the file LICENSE.GPL included in the packaging of this
25 ** file. Please review the following information to ensure the GNU General
26 ** Public License version 3.0 requirements will be met:
27 ** http://www.gnu.org/copyleft/gpl.html.
30 ** Alternatively, this file may be used in accordance with the terms and
31 ** conditions contained in a signed written agreement between you and Nokia.
40 ****************************************************************************/
42 #ifndef QQMLENGINE_P_H
43 #define QQMLENGINE_P_H
49 // This file is not part of the Qt API. It exists purely as an
50 // implementation detail. This header file may change from version to
51 // version without notice, or even be removed.
56 #include "qqmlengine.h"
58 #include "qqmltypeloader_p.h"
59 #include "qqmlimport_p.h"
60 #include <private/qpodvector_p.h>
62 #include "qqmlvaluetype_p.h"
63 #include "qqmlcontext.h"
64 #include "qqmlcontext_p.h"
65 #include "qqmlexpression.h"
66 #include "qqmlproperty_p.h"
67 #include "qqmlpropertycache_p.h"
68 #include "qqmlmetatype_p.h"
69 #include "qqmldirparser_p.h"
70 #include <private/qintrusivelist_p.h>
71 #include <private/qrecyclepool_p.h>
73 #include <QtCore/qlist.h>
74 #include <QtCore/qpair.h>
75 #include <QtCore/qstack.h>
76 #include <QtCore/qmutex.h>
77 #include <QtCore/qstring.h>
78 #include <QtCore/qthread.h>
80 #include <private/qobject_p.h>
82 #include <private/qv8engine_p.h>
83 #include <private/qjsengine_p.h>
89 class QQmlContextPrivate;
91 class QQmlImportDatabase;
93 class QNetworkAccessManager;
94 class QQmlNetworkAccessManagerFactory;
95 class QQmlAbstractBinding;
96 class QQmlTypeNameCache;
97 class QQmlComponentAttached;
99 class QQmlDelayedError;
100 class QQuickWorkerScriptEngine;
105 // This needs to be declared here so that the pool for it can live in QQmlEnginePrivate.
106 // The inline method definitions are in qqmlexpression_p.h
107 class QQmlJavaScriptExpressionGuard : public QQmlNotifierEndpoint
110 inline QQmlJavaScriptExpressionGuard(QQmlJavaScriptExpression *);
112 static inline void endpointCallback(QQmlNotifierEndpoint *, void **);
113 static inline QQmlJavaScriptExpressionGuard *New(QQmlJavaScriptExpression *e,
115 inline void Delete();
117 QQmlJavaScriptExpression *expression;
118 QQmlJavaScriptExpressionGuard *next;
121 class Q_QML_EXPORT QQmlEnginePrivate : public QJSEnginePrivate
123 Q_DECLARE_PUBLIC(QQmlEngine)
125 QQmlEnginePrivate(QQmlEngine *);
126 ~QQmlEnginePrivate();
130 class PropertyCapture {
132 inline virtual ~PropertyCapture() {}
133 virtual void captureProperty(QQmlNotifier *) = 0;
134 virtual void captureProperty(QObject *, int, int) = 0;
137 PropertyCapture *propertyCapture;
138 inline void captureProperty(QQmlNotifier *);
139 inline void captureProperty(QObject *, int, int);
141 QRecyclePool<QQmlJavaScriptExpressionGuard> jsExpressionGuardPool;
143 QQmlContext *rootContext;
146 bool outputWarningsToStdErr;
148 QQmlContextData *sharedContext;
149 QObject *sharedScope;
151 // Registered cleanup handlers
152 QQmlCleanup *cleanup;
154 // Bindings that have had errors during startup
155 QQmlDelayedError *erroredBindings;
156 int inProgressCreations;
158 QV8Engine *v8engine() const { return q_func()->handle(); }
160 QQuickWorkerScriptEngine *getWorkerScriptEngine();
161 QQuickWorkerScriptEngine *workerScriptEngine;
165 typedef QPair<QQmlGuard<QObject>,int> FinalizeCallback;
166 void registerFinalizeCallback(QObject *obj, int index);
170 QNetworkAccessManager *createNetworkAccessManager(QObject *parent) const;
171 QNetworkAccessManager *getNetworkAccessManager() const;
172 mutable QNetworkAccessManager *networkAccessManager;
173 mutable QQmlNetworkAccessManagerFactory *networkAccessManagerFactory;
175 QHash<QString,QSharedPointer<QQmlImageProviderBase> > imageProviders;
177 // Scarce resources are "exceptionally high cost" QVariant types where allowing the
178 // normal JavaScript GC to clean them up is likely to lead to out-of-memory or other
179 // out-of-resource situations. When such a resource is passed into JavaScript we
180 // add it to the scarceResources list and it is destroyed when we return from the
181 // JavaScript execution that created it. The user can prevent this behavior by
182 // calling preserve() on the object which removes it from this scarceResource list.
183 class ScarceResourceData {
185 ScarceResourceData(const QVariant &data) : data(data) {}
187 QIntrusiveListNode node;
189 QIntrusiveList<ScarceResourceData, &ScarceResourceData::node> scarceResources;
190 int scarceResourcesRefCount;
191 void referenceScarceResources();
192 void dereferenceScarceResources();
194 QQmlTypeLoader typeLoader;
195 QQmlImportDatabase importDatabase;
197 QString offlineStoragePath;
199 mutable quint32 uniqueId;
200 inline quint32 getUniqueId() const {
204 QQmlValueTypeFactory valueTypes;
206 // Unfortunate workaround to avoid a circular dependency between
207 // qqmlengine_p.h and qqmlincubator_p.h
209 QIntrusiveListNode next;
210 // Unfortunate workaround for MSVC
211 QIntrusiveListNode nextWaitingFor;
213 QIntrusiveList<Incubator, &Incubator::next> incubatorList;
214 unsigned int incubatorCount;
215 QQmlIncubationController *incubationController;
216 void incubate(QQmlIncubator &, QQmlContextData *);
218 // These methods may be called from any thread
219 inline bool isEngineThread() const;
220 inline static bool isEngineThread(const QQmlEngine *);
222 inline void deleteInEngineThread(T *);
224 inline static void deleteInEngineThread(QQmlEngine *, T *);
226 // These methods may be called from the loader thread
227 QQmlMetaType::ModuleApiInstance *moduleApiInstance(const QQmlMetaType::ModuleApi &module);
229 // These methods may be called from the loader thread
230 inline QQmlPropertyCache *cache(QObject *obj);
231 inline QQmlPropertyCache *cache(const QMetaObject *);
232 inline QQmlPropertyCache *cache(QQmlType *, int, QQmlError &error);
234 // These methods may be called from the loader thread
236 QObject *toQObject(const QVariant &, bool *ok = 0) const;
237 QQmlMetaType::TypeCategory typeCategory(int) const;
238 bool isList(int) const;
239 int listType(int) const;
240 const QMetaObject *rawMetaObjectForType(int) const;
241 const QMetaObject *metaObjectForType(int) const;
242 void registerCompositeType(QQmlCompiledData *);
245 void warning(const QQmlError &);
246 void warning(const QList<QQmlError> &);
247 static void warning(QQmlEngine *, const QQmlError &);
248 static void warning(QQmlEngine *, const QList<QQmlError> &);
249 static void warning(QQmlEnginePrivate *, const QQmlError &);
250 static void warning(QQmlEnginePrivate *, const QList<QQmlError> &);
252 inline static QV8Engine *getV8Engine(QQmlEngine *e);
253 inline static QQmlEnginePrivate *get(QQmlEngine *e);
254 inline static const QQmlEnginePrivate *get(const QQmlEngine *e);
255 inline static QQmlEnginePrivate *get(QQmlContext *c);
256 inline static QQmlEnginePrivate *get(QQmlContextData *c);
257 inline static QQmlEngine *get(QQmlEnginePrivate *p);
259 static void registerBaseTypes(const char *uri, int versionMajor, int versionMinor);
260 static void defineModule();
262 static bool qml_debugging_enabled;
264 mutable QMutex mutex;
267 // Locker locks the QQmlEnginePrivate data structures for read and write, if necessary.
268 // Currently, locking is only necessary if the threaded loader is running concurrently. If it is
269 // either idle, or is running with the main thread blocked, no locking is necessary. This way
270 // we only pay for locking when we have to.
271 // Consequently, this class should only be used to protect simple accesses or modifications of the
272 // QQmlEnginePrivate structures or operations that can be guarenteed not to start activity
273 // on the loader thread.
274 // The Locker API is identical to QMutexLocker. Locker reuses the QQmlEnginePrivate::mutex
275 // QMutex instance and multiple Lockers are recursive in the same thread.
279 inline Locker(const QQmlEngine *);
280 inline Locker(const QQmlEnginePrivate *);
283 inline void unlock();
284 inline void relock();
287 const QQmlEnginePrivate *m_ep;
291 // Must be called locked
292 QQmlPropertyCache *createCache(const QMetaObject *);
293 QQmlPropertyCache *createCache(QQmlType *, int, QQmlError &error);
295 // These members must be protected by a QQmlEnginePrivate::Locker as they are required by
296 // the threaded loader. Only access them through their respective accessor methods.
297 QHash<QQmlMetaType::ModuleApi, QQmlMetaType::ModuleApiInstance *> moduleApiInstances;
298 QHash<const QMetaObject *, QQmlPropertyCache *> propertyCache;
299 QHash<QPair<QQmlType *, int>, QQmlPropertyCache *> typePropertyCache;
300 QHash<int, int> m_qmlLists;
301 QHash<int, QQmlCompiledData *> m_compositeTypes;
303 // These members is protected by the full QQmlEnginePrivate::mutex mutex
304 struct Deletable { Deletable():next(0) {} virtual ~Deletable() {} Deletable *next; };
305 QFieldList<Deletable, &Deletable::next> toDeleteInEngineThread;
306 void doDeleteInEngineThread();
309 QQmlEnginePrivate::Locker::Locker(const QQmlEngine *e)
310 : m_ep(QQmlEnginePrivate::get(e))
315 QQmlEnginePrivate::Locker::Locker(const QQmlEnginePrivate *e)
316 : m_ep(e), m_locked(false)
321 QQmlEnginePrivate::Locker::~Locker()
326 void QQmlEnginePrivate::Locker::unlock()
329 m_ep->mutex.unlock();
334 void QQmlEnginePrivate::Locker::relock()
337 if (m_ep->typeLoader.isConcurrent()) {
344 Returns true if the calling thread is the QQmlEngine thread.
346 bool QQmlEnginePrivate::isEngineThread() const
348 Q_Q(const QQmlEngine);
349 return QThread::currentThread() == q->thread();
353 Returns true if the calling thread is the QQmlEngine \a engine thread.
355 bool QQmlEnginePrivate::isEngineThread(const QQmlEngine *engine)
358 return QQmlEnginePrivate::get(engine)->isEngineThread();
362 Delete \a value in the engine thread. If the calling thread is the engine
363 thread, \a value will be deleted immediately.
365 This method should be used for *any* type that has resources that need to
366 be freed in the engine thread. This is generally types that use V8 handles.
367 As there is some small overhead in checking the current thread, it is best
368 practice to check if any V8 handles actually need to be freed and delete
369 the instance directly if not.
372 void QQmlEnginePrivate::deleteInEngineThread(T *value)
377 if (isEngineThread()) {
380 struct I : public Deletable {
381 I(T *value) : value(value) {}
382 ~I() { delete value; }
387 bool wasEmpty = toDeleteInEngineThread.isEmpty();
388 toDeleteInEngineThread.append(i);
391 QCoreApplication::postEvent(q, new QEvent(QEvent::User));
396 Delete \a value in the \a engine thread. If the calling thread is the engine
397 thread, \a value will be deleted immediately.
400 void QQmlEnginePrivate::deleteInEngineThread(QQmlEngine *engine, T *value)
403 QQmlEnginePrivate::get(engine)->deleteInEngineThread<T>(value);
407 Returns a QQmlPropertyCache for \a obj if one is available.
409 If \a obj is null, being deleted or contains a dynamic meta object 0
412 The returned cache is not referenced, so if it is to be stored, call addref().
414 XXX thread There is a potential future race condition in this and all the cache()
415 functions. As the QQmlPropertyCache is returned unreferenced, when called
416 from the loader thread, it is possible that the cache will have been dereferenced
417 and deleted before the loader thread has a chance to use or reference it. This
418 can't currently happen as the cache holds a reference to the
419 QQmlPropertyCache until the QQmlEngine is destroyed.
421 QQmlPropertyCache *QQmlEnginePrivate::cache(QObject *obj)
423 if (!obj || QObjectPrivate::get(obj)->metaObject || QObjectPrivate::get(obj)->wasDeleted)
427 const QMetaObject *mo = obj->metaObject();
428 QQmlPropertyCache *rv = propertyCache.value(mo);
429 if (!rv) rv = createCache(mo);
434 Returns a QQmlPropertyCache for \a metaObject.
436 As the cache is persisted for the life of the engine, \a metaObject must be
437 a static "compile time" meta-object, or a meta-object that is otherwise known to
438 exist for the lifetime of the QQmlEngine.
440 The returned cache is not referenced, so if it is to be stored, call addref().
442 QQmlPropertyCache *QQmlEnginePrivate::cache(const QMetaObject *metaObject)
444 Q_ASSERT(metaObject);
447 QQmlPropertyCache *rv = propertyCache.value(metaObject);
448 if (!rv) rv = createCache(metaObject);
453 Returns a QQmlPropertyCache for \a type with \a minorVersion.
455 The returned cache is not referenced, so if it is to be stored, call addref().
457 QQmlPropertyCache *QQmlEnginePrivate::cache(QQmlType *type, int minorVersion, QQmlError &error)
461 if (minorVersion == -1 || !type->containsRevisionedAttributes())
462 return cache(type->metaObject());
465 QQmlPropertyCache *rv = typePropertyCache.value(qMakePair(type, minorVersion));
466 if (!rv) rv = createCache(type, minorVersion, error);
470 QV8Engine *QQmlEnginePrivate::getV8Engine(QQmlEngine *e)
472 return e->d_func()->v8engine();
475 QQmlEnginePrivate *QQmlEnginePrivate::get(QQmlEngine *e)
480 const QQmlEnginePrivate *QQmlEnginePrivate::get(const QQmlEngine *e)
485 QQmlEnginePrivate *QQmlEnginePrivate::get(QQmlContext *c)
487 return (c && c->engine()) ? QQmlEnginePrivate::get(c->engine()) : 0;
490 QQmlEnginePrivate *QQmlEnginePrivate::get(QQmlContextData *c)
492 return (c && c->engine) ? QQmlEnginePrivate::get(c->engine) : 0;
495 QQmlEngine *QQmlEnginePrivate::get(QQmlEnginePrivate *p)
500 void QQmlEnginePrivate::captureProperty(QQmlNotifier *n)
503 propertyCapture->captureProperty(n);
506 void QQmlEnginePrivate::captureProperty(QObject *o, int c, int n)
509 propertyCapture->captureProperty(o, c, n);
514 #endif // QQMLENGINE_P_H