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
104// This needs to be declared here so that the pool for it can live in QQmlEnginePrivate.
105// The inline method definitions are in qqmljavascriptexpression_p.h
106class QQmlJavaScriptExpressionGuard : public QQmlNotifierEndpoint
107{
108public:
109 inline QQmlJavaScriptExpressionGuard(QQmlJavaScriptExpression *);
110
111 static inline QQmlJavaScriptExpressionGuard *New(QQmlJavaScriptExpression *e,
112 QQmlEngine *engine);
113 inline void Delete();
114
115 QQmlJavaScriptExpression *expression;
116 QQmlJavaScriptExpressionGuard *next;
117};
118
119class Q_QML_PRIVATE_EXPORT QQmlEnginePrivate : public QJSEnginePrivate
120{
121 Q_DECLARE_PUBLIC(QQmlEngine)
122public:
123 QQmlEnginePrivate(QQmlEngine *);
124 ~QQmlEnginePrivate() override;
125
126 void init();
127 // No mutex protecting baseModulesUninitialized, because use outside QQmlEngine
128 // is just qmlClearTypeRegistrations (which can't be called while an engine exists)
129 static bool baseModulesUninitialized;
130
131 QQmlPropertyCapture *propertyCapture;
132
133 QRecyclePool<QQmlJavaScriptExpressionGuard> jsExpressionGuardPool;
134
135 QQmlContext *rootContext;
136
137#if !QT_CONFIG(qml_debug)
138 static const quintptr profiler = 0;
139#else
140 QQmlProfiler *profiler;
141#endif
142
143 bool outputWarningsToMsgLog;
144
145 // Registered cleanup handlers
146 QQmlCleanup *cleanup;
147
148 // Bindings that have had errors during startup
149 QQmlDelayedError *erroredBindings;
150 int inProgressCreations;
151
152 QV4::ExecutionEngine *v4engine() const { return q_func()->handle(); }
153
154#if QT_CONFIG(qml_worker_script)
155 QThread *workerScriptEngine;
156#endif
157
158 QUrl baseUrl;
159
160 typedef QPair<QPointer<QObject>,int> FinalizeCallback;
161 void registerFinalizeCallback(QObject *obj, int index);
162
163 QQmlObjectCreator *activeObjectCreator;
164#if QT_CONFIG(qml_network)
165 QNetworkAccessManager *createNetworkAccessManager(QObject *parent) const;
166 QNetworkAccessManager *getNetworkAccessManager() const;
167 mutable QNetworkAccessManager *networkAccessManager;
168 mutable QQmlNetworkAccessManagerFactory *networkAccessManagerFactory;
169#endif
170 QHash<QString,QSharedPointer<QQmlImageProviderBase> > imageProviders;
171 QSharedPointer<QQmlImageProviderBase> imageProvider(const QString &providerId) const;
172
173
174 QQmlAbstractUrlInterceptor* urlInterceptor;
175
176 int scarceResourcesRefCount;
177 void referenceScarceResources();
178 void dereferenceScarceResources();
179
180 QQmlImportDatabase importDatabase;
181 QQmlTypeLoader typeLoader;
182
183 QString offlineStoragePath;
184
185 mutable quint32 uniqueId;
186 inline quint32 getUniqueId() const {
187 return uniqueId++;
188 }
189
190 // Unfortunate workaround to avoid a circular dependency between
191 // qqmlengine_p.h and qqmlincubator_p.h
192 struct Incubator : public QSharedData {
193 QIntrusiveListNode next;
194 // Unfortunate workaround for MSVC
195 QIntrusiveListNode nextWaitingFor;
196 };
197 QIntrusiveList<Incubator, &Incubator::next> incubatorList;
198 unsigned int incubatorCount;
199 QQmlIncubationController *incubationController;
200 void incubate(QQmlIncubator &, QQmlContextData *);
201
202 // These methods may be called from any thread
203 inline bool isEngineThread() const;
204 inline static bool isEngineThread(const QQmlEngine *);
205 template<typename T>
206 inline void deleteInEngineThread(T *);
207 template<typename T>
208 inline static void deleteInEngineThread(QQmlEnginePrivate *, T *);
209 QString offlineStorageDatabaseDirectory() const;
210
211 // These methods may be called from the loader thread
212 inline QQmlPropertyCache *cache(const QQmlType &, int);
213 using QJSEnginePrivate::cache;
214
215 // These methods may be called from the loader thread
216 bool isQObject(int);
217 QObject *toQObject(const QVariant &, bool *ok = nullptr) const;
218 QQmlMetaType::TypeCategory typeCategory(int) const;
219 bool isList(int) const;
220 int listType(int) const;
221 QQmlMetaObject rawMetaObjectForType(int) const;
222 QQmlMetaObject metaObjectForType(int) const;
223 QQmlPropertyCache *propertyCacheForType(int);
224 QQmlPropertyCache *rawPropertyCacheForType(int, int minorVersion = -1);
225 void registerInternalCompositeType(QV4::ExecutableCompilationUnit *compilationUnit);
226 void unregisterInternalCompositeType(QV4::ExecutableCompilationUnit *compilationUnit);
227
228 bool isTypeLoaded(const QUrl &url) const;
229 bool isScriptLoaded(const QUrl &url) const;
230
231 template <typename T>
232 T singletonInstance(const QQmlType &type);
233 void destroySingletonInstance(const QQmlType &type);
234
235 void sendQuit();
236 void sendExit(int retCode = 0);
237 void warning(const QQmlError &);
238 void warning(const QList<QQmlError> &);
239 static void warning(QQmlEngine *, const QQmlError &);
240 static void warning(QQmlEngine *, const QList<QQmlError> &);
241 static void warning(QQmlEnginePrivate *, const QQmlError &);
242 static void warning(QQmlEnginePrivate *, const QList<QQmlError> &);
243
244 inline static QV4::ExecutionEngine *getV4Engine(QQmlEngine *e);
245 inline static QQmlEnginePrivate *get(QQmlEngine *e);
246 inline static const QQmlEnginePrivate *get(const QQmlEngine *e);
247 inline static QQmlEnginePrivate *get(QQmlContext *c);
248 inline static QQmlEnginePrivate *get(QQmlContextData *c);
249 inline static QQmlEngine *get(QQmlEnginePrivate *p);
250 inline static QQmlEnginePrivate *get(QV4::ExecutionEngine *e);
251
252 static QList<QQmlError> qmlErrorFromDiagnostics(const QString &fileName, const QList<QQmlJS::DiagnosticMessage> &diagnosticMessages);
253
254 static void defineModule();
255#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
256 static void registerQuickTypes();
257#endif
258
259 static bool designerMode();
260 static void activateDesignerMode();
261
262 static bool qml_debugging_enabled;
263
264 mutable QMutex networkAccessManagerMutex;
265
266private:
267 QHash<QQmlType, QJSValue> singletonInstances;
268
269 // These members must be protected by a QQmlEnginePrivate::Locker as they are required by
270 // the threaded loader. Only access them through their respective accessor methods.
271 QHash<int, QV4::ExecutableCompilationUnit *> m_compositeTypes;
272 static bool s_designerMode;
273
274 // These members is protected by the full QQmlEnginePrivate::mutex mutex
275 struct Deletable { Deletable():next(nullptr) {} virtual ~Deletable() {} Deletable *next; };
276 QFieldList<Deletable, &Deletable::next> toDeleteInEngineThread;
277 void doDeleteInEngineThread();
278
279 void cleanupScarceResources();
280};
281
282/*
283 This function should be called prior to evaluation of any js expression,
284 so that scarce resources are not freed prematurely (eg, if there is a
285 nested javascript expression).
286 */
287inline void QQmlEnginePrivate::referenceScarceResources()
288{
289 scarceResourcesRefCount += 1;
290}
291
292/*
293 This function should be called after evaluation of the js expression is
294 complete, and so the scarce resources may be freed safely.
295 */
296inline void QQmlEnginePrivate::dereferenceScarceResources()
297{
298 Q_ASSERT(scarceResourcesRefCount > 0);
299 scarceResourcesRefCount -= 1;
300
301 // if the refcount is zero, then evaluation of the "top level"
302 // expression must have completed. We can safely release the
303 // scarce resources.
304 if (Q_LIKELY(scarceResourcesRefCount == 0)) {
305 QV4::ExecutionEngine *engine = v4engine();
306 if (Q_UNLIKELY(!engine->scarceResources.isEmpty())) {
307 cleanupScarceResources();
308 }
309 }
310}
311
312/*!
313Returns true if the calling thread is the QQmlEngine thread.
314*/
315bool QQmlEnginePrivate::isEngineThread() const
316{
317
318 return QThread::currentThread() == q_ptr->thread();
319}
320
321/*!
322Returns true if the calling thread is the QQmlEngine \a engine thread.
323*/
324bool QQmlEnginePrivate::isEngineThread(const QQmlEngine *engine)
325{
326 Q_ASSERT(engine);
327 return QQmlEnginePrivate::get(engine)->isEngineThread();
328}
329
330/*!
331Delete \a value in the engine thread. If the calling thread is the engine
332thread, \a value will be deleted immediately.
333
334This method should be used for *any* type that has resources that need to
335be freed in the engine thread. This is generally types that use V8 handles.
336As there is some small overhead in checking the current thread, it is best
337practice to check if any V8 handles actually need to be freed and delete
338the instance directly if not.
339*/
340template<typename T>
341void QQmlEnginePrivate::deleteInEngineThread(T *value)
342{
343 Q_ASSERT(value);
344 if (isEngineThread()) {
345 delete value;
346 } else {
347 struct I : public Deletable {
348 I(T *value) : value(value) {}
349 ~I() override { delete value; }
350 T *value;
351 };
352 I *i = new I(value);
353 mutex.lock();
354 bool wasEmpty = toDeleteInEngineThread.isEmpty();
355 toDeleteInEngineThread.append(i);
356 mutex.unlock();
357 if (wasEmpty)
358 QCoreApplication::postEvent(q_ptr, new QEvent(QEvent::User));
359 }
360}
361
362/*!
363Delete \a value in the \a engine thread. If the calling thread is the engine
364thread, \a value will be deleted immediately.
365*/
366template<typename T>
367void QQmlEnginePrivate::deleteInEngineThread(QQmlEnginePrivate *engine, T *value)
368{
369 Q_ASSERT(engine);
370 engine->deleteInEngineThread<T>(value);
371}
372
373/*!
374Returns a QQmlPropertyCache for \a type with \a minorVersion.
375
376The returned cache is not referenced, so if it is to be stored, call addref().
377*/
378QQmlPropertyCache *QQmlEnginePrivate::cache(const QQmlType &type, int minorVersion)
379{
380 Q_ASSERT(type.isValid());
381
382 if (minorVersion == -1 || !type.containsRevisionedAttributes())
383 return cache(type.metaObject(), minorVersion);
384
385 Locker locker(this);
386 return QQmlMetaType::propertyCache(type, minorVersion);
387}
388
389QV4::ExecutionEngine *QQmlEnginePrivate::getV4Engine(QQmlEngine *e)
390{
391 Q_ASSERT(e);
392
393 return e->handle();
394}
395
396QQmlEnginePrivate *QQmlEnginePrivate::get(QQmlEngine *e)
397{
398 Q_ASSERT(e);
399
400 return e->d_func();
401}
402
403const QQmlEnginePrivate *QQmlEnginePrivate::get(const QQmlEngine *e)
404{
405 Q_ASSERT(e);
406
407 return e ? e->d_func() : nullptr;
408}
409
410QQmlEnginePrivate *QQmlEnginePrivate::get(QQmlContext *c)
411{
412 return (c && c->engine()) ? QQmlEnginePrivate::get(c->engine()) : nullptr;
413}
414
415QQmlEnginePrivate *QQmlEnginePrivate::get(QQmlContextData *c)
416{
417 return (c && c->engine) ? QQmlEnginePrivate::get(c->engine) : nullptr;
418}
419
420QQmlEngine *QQmlEnginePrivate::get(QQmlEnginePrivate *p)
421{
422 Q_ASSERT(p);
423
424 return p->q_func();
425}
426
427QQmlEnginePrivate *QQmlEnginePrivate::get(QV4::ExecutionEngine *e)
428{
429 QQmlEngine *qmlEngine = e->qmlEngine();
430 if (!qmlEngine)
431 return nullptr;
432 return get(qmlEngine);
433}
434
435template<>
436Q_QML_PRIVATE_EXPORT QJSValue QQmlEnginePrivate::singletonInstance<QJSValue>(const QQmlType &type);
437
438template<typename T>
439T QQmlEnginePrivate::singletonInstance(const QQmlType &type) {
440 return qobject_cast<T>(singletonInstance<QJSValue>(type).toQObject());
441}
442
443QT_END_NAMESPACE
444
445#endif // QQMLENGINE_P_H
446