1/****************************************************************************
2**
3** Copyright (C) 2016 The Qt Company Ltd.
4** Contact: https://www.qt.io/licensing/
5**
6** This file is part of the QtQml module of the Qt Toolkit.
7**
8** $QT_BEGIN_LICENSE:LGPL$
9** Commercial License Usage
10** Licensees holding valid commercial Qt licenses may use this file in
11** accordance with the commercial license agreement provided with the
12** Software or, alternatively, in accordance with the terms contained in
13** a written agreement between you and The Qt Company. For licensing terms
14** and conditions see https://www.qt.io/terms-conditions. For further
15** information use the contact form at https://www.qt.io/contact-us.
16**
17** GNU Lesser General Public License Usage
18** Alternatively, this file may be used under the terms of the GNU Lesser
19** General Public License version 3 as published by the Free Software
20** Foundation and appearing in the file LICENSE.LGPL3 included in the
21** packaging of this file. Please review the following information to
22** ensure the GNU Lesser General Public License version 3 requirements
23** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
24**
25** GNU General Public License Usage
26** Alternatively, this file may be used under the terms of the GNU
27** General Public License version 2.0 or (at your option) the GNU General
28** Public license version 3 or any later version approved by the KDE Free
29** Qt Foundation. The licenses are as published by the Free Software
30** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
31** included in the packaging of this file. Please review the following
32** information to ensure the GNU General Public License requirements will
33** be met: https://www.gnu.org/licenses/gpl-2.0.html and
34** https://www.gnu.org/licenses/gpl-3.0.html.
35**
36** $QT_END_LICENSE$
37**
38****************************************************************************/
39
40#ifndef QQMLENGINE_P_H
41#define QQMLENGINE_P_H
42
43//
44// W A R N I N G
45// -------------
46//
47// This file is not part of the Qt API. It exists purely as an
48// implementation detail. This header file may change from version to
49// version without notice, or even be removed.
50//
51// We mean it.
52//
53
54#include "qqmlengine.h"
55
56#include "qqmltypeloader_p.h"
57#include "qqmlimport_p.h"
58#include <private/qpodvector_p.h>
59#include "qqml.h"
60#include "qqmlvaluetype_p.h"
61#include "qqmlcontext.h"
62#include "qqmlcontext_p.h"
63#include "qqmlexpression.h"
64#include "qqmlproperty_p.h"
65#include "qqmlmetatype_p.h"
66#include <private/qintrusivelist_p.h>
67#include <private/qrecyclepool_p.h>
68#include <private/qfieldlist_p.h>
69#include <private/qv4engine_p.h>
70
71#include <QtCore/qlist.h>
72#include <QtCore/qpair.h>
73#include <QtCore/qstack.h>
74#include <QtCore/qmutex.h>
75#include <QtCore/qstring.h>
76#include <QtCore/qthread.h>
77
78#include <private/qobject_p.h>
79
80#include <private/qjsengine_p.h>
81#include <private/qqmldirparser_p.h>
82
83QT_BEGIN_NAMESPACE
84
85class QQmlContext;
86class QQmlEngine;
87class QQmlContextPrivate;
88class QQmlExpression;
89class QQmlImportDatabase;
90class QNetworkReply;
91class QNetworkAccessManager;
92class QQmlNetworkAccessManagerFactory;
93class QQmlTypeNameCache;
94class QQmlComponentAttached;
95class QQmlCleanup;
96class QQmlDelayedError;
97class QQmlObjectCreator;
98class QDir;
99class QQmlIncubator;
100class QQmlProfiler;
101class QQmlPropertyCapture;
102class QQmlMetaObject;
103
104struct QObjectForeign {
105 Q_GADGET
106 QML_FOREIGN(QObject)
107 QML_NAMED_ELEMENT(QtObject)
108 Q_CLASSINFO("QML.Root", "QML")
109};
110
111// This needs to be declared here so that the pool for it can live in QQmlEnginePrivate.
112// The inline method definitions are in qqmljavascriptexpression_p.h
113class QQmlJavaScriptExpressionGuard : public QQmlNotifierEndpoint
114{
115public:
116 inline QQmlJavaScriptExpressionGuard(QQmlJavaScriptExpression *);
117
118 static inline QQmlJavaScriptExpressionGuard *New(QQmlJavaScriptExpression *e,
119 QQmlEngine *engine);
120 inline void Delete();
121
122 QQmlJavaScriptExpression *expression;
123 QQmlJavaScriptExpressionGuard *next;
124};
125
126class Q_QML_PRIVATE_EXPORT QQmlEnginePrivate : public QJSEnginePrivate
127{
128 Q_DECLARE_PUBLIC(QQmlEngine)
129public:
130 QQmlEnginePrivate(QQmlEngine *);
131 ~QQmlEnginePrivate() override;
132
133 void init();
134 // No mutex protecting baseModulesUninitialized, because use outside QQmlEngine
135 // is just qmlClearTypeRegistrations (which can't be called while an engine exists)
136 static bool baseModulesUninitialized;
137
138 QQmlPropertyCapture *propertyCapture;
139
140 QRecyclePool<QQmlJavaScriptExpressionGuard> jsExpressionGuardPool;
141
142 QQmlContext *rootContext;
143
144#if !QT_CONFIG(qml_debug)
145 static const quintptr profiler = 0;
146#else
147 QQmlProfiler *profiler;
148#endif
149
150 bool outputWarningsToMsgLog;
151
152 // Registered cleanup handlers
153 QQmlCleanup *cleanup;
154
155 // Bindings that have had errors during startup
156 QQmlDelayedError *erroredBindings;
157 int inProgressCreations;
158
159 QV4::ExecutionEngine *v4engine() const { return q_func()->handle(); }
160
161#if QT_CONFIG(qml_worker_script)
162 QThread *workerScriptEngine;
163#endif
164
165 QUrl baseUrl;
166
167 typedef QPair<QPointer<QObject>,int> FinalizeCallback;
168 void registerFinalizeCallback(QObject *obj, int index);
169
170 QQmlObjectCreator *activeObjectCreator;
171#if QT_CONFIG(qml_network)
172 QNetworkAccessManager *createNetworkAccessManager(QObject *parent) const;
173 QNetworkAccessManager *getNetworkAccessManager() const;
174 mutable QNetworkAccessManager *networkAccessManager;
175 mutable QQmlNetworkAccessManagerFactory *networkAccessManagerFactory;
176#endif
177 QHash<QString,QSharedPointer<QQmlImageProviderBase> > imageProviders;
178 QSharedPointer<QQmlImageProviderBase> imageProvider(const QString &providerId) const;
179
180
181 QQmlAbstractUrlInterceptor* urlInterceptor;
182
183 int scarceResourcesRefCount;
184 void referenceScarceResources();
185 void dereferenceScarceResources();
186
187 QQmlImportDatabase importDatabase;
188 QQmlTypeLoader typeLoader;
189
190 QString offlineStoragePath;
191
192 mutable quint32 uniqueId;
193 inline quint32 getUniqueId() const {
194 return uniqueId++;
195 }
196
197 // Unfortunate workaround to avoid a circular dependency between
198 // qqmlengine_p.h and qqmlincubator_p.h
199 struct Incubator : public QSharedData {
200 QIntrusiveListNode next;
201 // Unfortunate workaround for MSVC
202 QIntrusiveListNode nextWaitingFor;
203 };
204 QIntrusiveList<Incubator, &Incubator::next> incubatorList;
205 unsigned int incubatorCount;
206 QQmlIncubationController *incubationController;
207 void incubate(QQmlIncubator &, QQmlContextData *);
208
209 // These methods may be called from any thread
210 inline bool isEngineThread() const;
211 inline static bool isEngineThread(const QQmlEngine *);
212 template<typename T>
213 inline void deleteInEngineThread(T *);
214 template<typename T>
215 inline static void deleteInEngineThread(QQmlEnginePrivate *, T *);
216 QString offlineStorageDatabaseDirectory() const;
217
218 // These methods may be called from the loader thread
219 inline QQmlPropertyCache *cache(const QQmlType &, int);
220 using QJSEnginePrivate::cache;
221
222 // These methods may be called from the loader thread
223 bool isQObject(int);
224 QObject *toQObject(const QVariant &, bool *ok = nullptr) const;
225 QQmlMetaType::TypeCategory typeCategory(int) const;
226 bool isList(int) const;
227 int listType(int) const;
228 QQmlMetaObject rawMetaObjectForType(int) const;
229 QQmlMetaObject metaObjectForType(int) const;
230 QQmlPropertyCache *propertyCacheForType(int);
231 QQmlPropertyCache *rawPropertyCacheForType(int, int minorVersion = -1);
232 void registerInternalCompositeType(QV4::ExecutableCompilationUnit *compilationUnit);
233 void unregisterInternalCompositeType(QV4::ExecutableCompilationUnit *compilationUnit);
234 QV4::ExecutableCompilationUnit *obtainExecutableCompilationUnit(int typeId);
235
236 bool isTypeLoaded(const QUrl &url) const;
237 bool isScriptLoaded(const QUrl &url) const;
238
239 template <typename T>
240 T singletonInstance(const QQmlType &type);
241 void destroySingletonInstance(const QQmlType &type);
242
243 void sendQuit();
244 void sendExit(int retCode = 0);
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> &);
251
252 inline static QV4::ExecutionEngine *getV4Engine(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);
258 inline static QQmlEnginePrivate *get(QV4::ExecutionEngine *e);
259
260 static QList<QQmlError> qmlErrorFromDiagnostics(const QString &fileName, const QList<QQmlJS::DiagnosticMessage> &diagnosticMessages);
261
262 static void defineModule();
263#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
264 static void registerQuickTypes();
265#endif
266
267 static bool designerMode();
268 static void activateDesignerMode();
269
270 static bool qml_debugging_enabled;
271
272 mutable QMutex networkAccessManagerMutex;
273
274 QQmlGadgetPtrWrapper *valueTypeInstance(int typeIndex)
275 {
276 auto it = cachedValueTypeInstances.find(typeIndex);
277 if (it != cachedValueTypeInstances.end())
278 return *it;
279
280 if (QQmlValueType *valueType = QQmlValueTypeFactory::valueType(typeIndex)) {
281 QQmlGadgetPtrWrapper *instance = new QQmlGadgetPtrWrapper(valueType, q_func());
282 cachedValueTypeInstances.insert(typeIndex, instance);
283 return instance;
284 }
285
286 return nullptr;
287 }
288
289private:
290 QHash<QQmlType, QJSValue> singletonInstances;
291 QHash<int, QQmlGadgetPtrWrapper *> cachedValueTypeInstances;
292
293 // These members must be protected by a QQmlEnginePrivate::Locker as they are required by
294 // the threaded loader. Only access them through their respective accessor methods.
295 QHash<int, QV4::ExecutableCompilationUnit *> m_compositeTypes;
296 static bool s_designerMode;
297
298 // These members is protected by the full QQmlEnginePrivate::mutex mutex
299 struct Deletable { Deletable():next(nullptr) {} virtual ~Deletable() {} Deletable *next; };
300 QFieldList<Deletable, &Deletable::next> toDeleteInEngineThread;
301 void doDeleteInEngineThread();
302
303 void cleanupScarceResources();
304};
305
306/*
307 This function should be called prior to evaluation of any js expression,
308 so that scarce resources are not freed prematurely (eg, if there is a
309 nested javascript expression).
310 */
311inline void QQmlEnginePrivate::referenceScarceResources()
312{
313 scarceResourcesRefCount += 1;
314}
315
316/*
317 This function should be called after evaluation of the js expression is
318 complete, and so the scarce resources may be freed safely.
319 */
320inline void QQmlEnginePrivate::dereferenceScarceResources()
321{
322 Q_ASSERT(scarceResourcesRefCount > 0);
323 scarceResourcesRefCount -= 1;
324
325 // if the refcount is zero, then evaluation of the "top level"
326 // expression must have completed. We can safely release the
327 // scarce resources.
328 if (Q_LIKELY(scarceResourcesRefCount == 0)) {
329 QV4::ExecutionEngine *engine = v4engine();
330 if (Q_UNLIKELY(!engine->scarceResources.isEmpty())) {
331 cleanupScarceResources();
332 }
333 }
334}
335
336/*!
337Returns true if the calling thread is the QQmlEngine thread.
338*/
339bool QQmlEnginePrivate::isEngineThread() const
340{
341
342 return QThread::currentThread() == q_ptr->thread();
343}
344
345/*!
346Returns true if the calling thread is the QQmlEngine \a engine thread.
347*/
348bool QQmlEnginePrivate::isEngineThread(const QQmlEngine *engine)
349{
350 Q_ASSERT(engine);
351 return QQmlEnginePrivate::get(engine)->isEngineThread();
352}
353
354/*!
355Delete \a value in the engine thread. If the calling thread is the engine
356thread, \a value will be deleted immediately.
357
358This method should be used for *any* type that has resources that need to
359be freed in the engine thread. This is generally types that use V8 handles.
360As there is some small overhead in checking the current thread, it is best
361practice to check if any V8 handles actually need to be freed and delete
362the instance directly if not.
363*/
364template<typename T>
365void QQmlEnginePrivate::deleteInEngineThread(T *value)
366{
367 Q_ASSERT(value);
368 if (isEngineThread()) {
369 delete value;
370 } else {
371 struct I : public Deletable {
372 I(T *value) : value(value) {}
373 ~I() override { delete value; }
374 T *value;
375 };
376 I *i = new I(value);
377 mutex.lock();
378 bool wasEmpty = toDeleteInEngineThread.isEmpty();
379 toDeleteInEngineThread.append(i);
380 mutex.unlock();
381 if (wasEmpty)
382 QCoreApplication::postEvent(q_ptr, new QEvent(QEvent::User));
383 }
384}
385
386/*!
387Delete \a value in the \a engine thread. If the calling thread is the engine
388thread, \a value will be deleted immediately.
389*/
390template<typename T>
391void QQmlEnginePrivate::deleteInEngineThread(QQmlEnginePrivate *engine, T *value)
392{
393 Q_ASSERT(engine);
394 engine->deleteInEngineThread<T>(value);
395}
396
397/*!
398Returns a QQmlPropertyCache for \a type with \a minorVersion.
399
400The returned cache is not referenced, so if it is to be stored, call addref().
401*/
402QQmlPropertyCache *QQmlEnginePrivate::cache(const QQmlType &type, int minorVersion)
403{
404 Q_ASSERT(type.isValid());
405
406 if (minorVersion == -1 || !type.containsRevisionedAttributes())
407 return cache(type.metaObject(), minorVersion);
408
409 Locker locker(this);
410 return QQmlMetaType::propertyCache(type, minorVersion);
411}
412
413QV4::ExecutionEngine *QQmlEnginePrivate::getV4Engine(QQmlEngine *e)
414{
415 Q_ASSERT(e);
416
417 return e->handle();
418}
419
420QQmlEnginePrivate *QQmlEnginePrivate::get(QQmlEngine *e)
421{
422 Q_ASSERT(e);
423
424 return e->d_func();
425}
426
427const QQmlEnginePrivate *QQmlEnginePrivate::get(const QQmlEngine *e)
428{
429 Q_ASSERT(e);
430
431 return e ? e->d_func() : nullptr;
432}
433
434QQmlEnginePrivate *QQmlEnginePrivate::get(QQmlContext *c)
435{
436 return (c && c->engine()) ? QQmlEnginePrivate::get(c->engine()) : nullptr;
437}
438
439QQmlEnginePrivate *QQmlEnginePrivate::get(QQmlContextData *c)
440{
441 return (c && c->engine) ? QQmlEnginePrivate::get(c->engine) : nullptr;
442}
443
444QQmlEngine *QQmlEnginePrivate::get(QQmlEnginePrivate *p)
445{
446 Q_ASSERT(p);
447
448 return p->q_func();
449}
450
451QQmlEnginePrivate *QQmlEnginePrivate::get(QV4::ExecutionEngine *e)
452{
453 QQmlEngine *qmlEngine = e->qmlEngine();
454 if (!qmlEngine)
455 return nullptr;
456 return get(qmlEngine);
457}
458
459template<>
460Q_QML_PRIVATE_EXPORT QJSValue QQmlEnginePrivate::singletonInstance<QJSValue>(const QQmlType &type);
461
462template<typename T>
463T QQmlEnginePrivate::singletonInstance(const QQmlType &type) {
464 return qobject_cast<T>(singletonInstance<QJSValue>(type).toQObject());
465}
466
467QT_END_NAMESPACE
468
469#endif // QQMLENGINE_P_H
470

source code of qtdeclarative/src/qml/qml/qqmlengine_p.h