1 /****************************************************************************
2 **
3 ** Copyright (C) 2019 The Qt Company Ltd.
4 ** Contact: https://www.qt.io/licensing/
5 **
6 ** This file is part of the tools applications 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 QV4EXECUTABLECOMPILATIONUNIT_P_H
41 #define QV4EXECUTABLECOMPILATIONUNIT_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 <private/qv4compileddata_p.h>
55 #include <private/qv4identifier_p.h>
56 #include <private/qqmlrefcount_p.h>
57 #include <private/qintrusivelist_p.h>
58 #include <private/qqmlpropertycachevector_p.h>
59 #include <private/qqmltype_p.h>
60 #include <private/qqmlnullablevalue_p.h>
61 #include <private/qqmlmetatype_p.h>
62 
63 QT_BEGIN_NAMESPACE
64 
65 class QQmlScriptData;
66 class QQmlEnginePrivate;
67 
68 struct InlineComponentData {
69 
70     InlineComponentData() = default;
InlineComponentDataInlineComponentData71     InlineComponentData(const CompositeMetaTypeIds &typeIds, int objectIndex, int nameIndex, int totalObjectCount, int totalBindingCount, int totalParserStatusCount)
72         :   typeIds(typeIds)
73           , objectIndex(objectIndex)
74           , nameIndex(nameIndex)
75           , totalObjectCount(totalObjectCount)
76           , totalBindingCount(totalBindingCount)
77           , totalParserStatusCount(totalParserStatusCount) {}
78 
79     CompositeMetaTypeIds typeIds;
80     int objectIndex = -1;
81     int nameIndex = -1;
82     int totalObjectCount = 0;
83     int totalBindingCount = 0;
84     int totalParserStatusCount = 0;
85 };
86 
87 namespace QV4 {
88 
89 // index is per-object binding index
90 typedef QVector<QQmlPropertyData*> BindingPropertyData;
91 
92 class CompilationUnitMapper;
93 struct ResolvedTypeReference;
94 // map from name index
95 // While this could be a hash, a map is chosen here to provide a stable
96 // order, which is used to calculating a check-sum on dependent meta-objects.
97 struct ResolvedTypeReferenceMap: public QMap<int, ResolvedTypeReference*>
98 {
99     bool addToHash(QCryptographicHash *hash, QQmlEngine *engine) const;
100 };
101 
102 class Q_QML_PRIVATE_EXPORT ExecutableCompilationUnit final: public CompiledData::CompilationUnit,
103                                                             public QQmlRefCount
104 {
105     Q_DISABLE_COPY_MOVE(ExecutableCompilationUnit)
106 public:
107     friend class QQmlRefPointer<ExecutableCompilationUnit>;
108 
create(CompiledData::CompilationUnit && compilationUnit)109     static QQmlRefPointer<ExecutableCompilationUnit> create(
110             CompiledData::CompilationUnit &&compilationUnit)
111     {
112         return QQmlRefPointer<ExecutableCompilationUnit>(
113                 new ExecutableCompilationUnit(std::move(compilationUnit)),
114                 QQmlRefPointer<ExecutableCompilationUnit>::Adopt);
115     }
116 
create()117     static QQmlRefPointer<ExecutableCompilationUnit> create()
118     {
119         return QQmlRefPointer<ExecutableCompilationUnit>(
120                 new ExecutableCompilationUnit,
121                 QQmlRefPointer<ExecutableCompilationUnit>::Adopt);
122     }
123 
124     QIntrusiveListNode nextCompilationUnit;
125     ExecutionEngine *engine = nullptr;
126     QQmlEnginePrivate *qmlEngine = nullptr; // only used in QML environment for composite types, not in plain QJSEngine case.
127 
128     // url() and fileName() shall be used to load the actual QML/JS code or to show errors or
129     // warnings about that code. They include any potential URL interceptions and thus represent the
130     // "physical" location of the code.
131     //
132     // finalUrl() and finalUrlString() shall be used to resolve further URLs referred to in the code
133     // They are _not_ intercepted and thus represent the "logical" name for the code.
134 
url()135     QUrl url() const { if (m_url.isNull) m_url = QUrl(fileName()); return m_url; }
finalUrl()136     QUrl finalUrl() const
137     {
138         if (m_finalUrl.isNull)
139             m_finalUrl = QUrl(finalUrlString());
140         return m_finalUrl;
141     }
142 
143     QV4::Lookup *runtimeLookups = nullptr;
144     QVector<QV4::Function *> runtimeFunctions;
145     QVector<QV4::Heap::InternalClass *> runtimeBlocks;
146     mutable QVector<QV4::Heap::Object *> templateObjects;
147     mutable QQmlNullableValue<QUrl> m_url;
148     mutable QQmlNullableValue<QUrl> m_finalUrl;
149 
150     // QML specific fields
151     QQmlPropertyCacheVector propertyCaches;
rootPropertyCache()152     QQmlRefPointer<QQmlPropertyCache> rootPropertyCache() const { return propertyCaches.at(/*root object*/0); }
153 
154     QQmlRefPointer<QQmlTypeNameCache> typeNameCache;
155 
156     // index is object index. This allows fast access to the
157     // property data when initializing bindings, avoiding expensive
158     // lookups by string (property name).
159     QVector<BindingPropertyData> bindingPropertyDataPerObject;
160 
161     // mapping from component object index (CompiledData::Unit object index that points to component) to identifier hash of named objects
162     // this is initialized on-demand by QQmlContextData
163     QHash<int, IdentifierHash> namedObjectsPerComponentCache;
164     inline IdentifierHash namedObjectsPerComponent(int componentObjectIndex);
165 
166     void finalizeCompositeType(QQmlEnginePrivate *qmlEngine, CompositeMetaTypeIds typeIdsForComponent);
167 
168     int m_totalBindingsCount = 0; // Number of bindings used in this type
169     int m_totalParserStatusCount = 0; // Number of instantiated types that are QQmlParserStatus subclasses
170     int m_totalObjectCount = 0; // Number of objects explicitly instantiated
171     int icRoot = -1;
172 
173     int totalBindingsCount() const;
174     int totalParserStatusCount() const;
175     int totalObjectCount() const;
176 
177     QVector<QQmlRefPointer<QQmlScriptData>> dependentScripts;
178     ResolvedTypeReferenceMap resolvedTypes;
resolvedType(int id)179     ResolvedTypeReference *resolvedType(int id) const { return resolvedTypes.value(id); }
180 
181     bool verifyChecksum(const CompiledData::DependentTypesHasher &dependencyHasher) const;
182 
183     CompositeMetaTypeIds typeIdsForComponent(int objectid = 0) const;
184 
185     int metaTypeId = -1;
186     int listMetaTypeId = -1;
187     bool isRegisteredWithEngine = false;
188 
189     QHash<int, InlineComponentData> inlineComponentData;
190 
191     QScopedPointer<CompilationUnitMapper> backingFile;
192 
193     // --- interface for QQmlPropertyCacheCreator
194     using CompiledObject = CompiledData::Object;
195     using CompiledFunction = CompiledData::Function;
196 
objectCount()197     int objectCount() const { return qmlData->nObjects; }
objectAt(int index)198     const CompiledObject *objectAt(int index) const
199     {
200         return qmlData->objectAt(index);
201     }
202 
importCount()203     int importCount() const { return qmlData->nImports; }
importAt(int index)204     const CompiledData::Import *importAt(int index) const
205     {
206         return qmlData->importAt(index);
207     }
208 
209     Heap::Object *templateObjectAt(int index) const;
210 
211     struct FunctionIterator
212     {
FunctionIteratorFunctionIterator213         FunctionIterator(const CompiledData::Unit *unit, const CompiledObject *object, int index)
214             : unit(unit), object(object), index(index) {}
215         const CompiledData::Unit *unit;
216         const CompiledObject *object;
217         int index;
218 
219         const CompiledFunction *operator->() const
220         {
221             return unit->functionAt(object->functionOffsetTable()[index]);
222         }
223 
224         void operator++() { ++index; }
225         bool operator==(const FunctionIterator &rhs) const { return index == rhs.index; }
226         bool operator!=(const FunctionIterator &rhs) const { return index != rhs.index; }
227     };
228 
objectFunctionsBegin(const CompiledObject * object)229     FunctionIterator objectFunctionsBegin(const CompiledObject *object) const
230     {
231         return FunctionIterator(data, object, 0);
232     }
233 
objectFunctionsEnd(const CompiledObject * object)234     FunctionIterator objectFunctionsEnd(const CompiledObject *object) const
235     {
236         return FunctionIterator(data, object, object->nFunctions);
237     }
238 
isESModule()239     bool isESModule() const
240     {
241         return data->flags & CompiledData::Unit::IsESModule;
242     }
243 
isSharedLibrary()244     bool isSharedLibrary() const
245     {
246         return data->flags & CompiledData::Unit::IsSharedLibrary;
247     }
248 
249     QStringList moduleRequests() const;
250     Heap::Module *instantiate(ExecutionEngine *engine);
resolveExport(QV4::String * exportName)251     const Value *resolveExport(QV4::String *exportName)
252     {
253         QVector<ResolveSetEntry> resolveSet;
254         return resolveExportRecursively(exportName, &resolveSet);
255     }
256 
exportedNames()257     QStringList exportedNames() const
258     {
259         QStringList names;
260         QVector<const ExecutableCompilationUnit*> exportNameSet;
261         getExportedNamesRecursively(&names, &exportNameSet);
262         names.sort();
263         auto last = std::unique(names.begin(), names.end());
264         names.erase(last, names.end());
265         return names;
266     }
267 
268     void evaluate();
269     void evaluateModuleRequests();
270 
271     QV4::Function *linkToEngine(QV4::ExecutionEngine *engine);
272     void unlink();
273 
274     void markObjects(MarkStack *markStack);
275 
276     bool loadFromDisk(const QUrl &url, const QDateTime &sourceTimeStamp, QString *errorString);
277 
278     static QString localCacheFilePath(const QUrl &url);
279     bool saveToDisk(const QUrl &unitUrl, QString *errorString);
280 
281     QString bindingValueAsString(const CompiledData::Binding *binding) const;
282     QString bindingValueAsScriptString(const CompiledData::Binding *binding) const;
bindingValueAsNumber(const CompiledData::Binding * binding)283     double bindingValueAsNumber(const CompiledData::Binding *binding) const
284     {
285         if (binding->type != CompiledData::Binding::Type_Number)
286             return 0.0;
287         return constants[binding->value.constantValueIndex].doubleValue();
288     }
289 
290     static bool verifyHeader(const CompiledData::Unit *unit, QDateTime expectedSourceTimeStamp,
291                              QString *errorString);
292 
293 protected:
totalStringCount()294     quint32 totalStringCount() const
295     { return data->stringTableSize; }
296 
297 private:
298     struct ResolveSetEntry
299     {
ResolveSetEntryResolveSetEntry300         ResolveSetEntry() {}
ResolveSetEntryResolveSetEntry301         ResolveSetEntry(ExecutableCompilationUnit *module, QV4::String *exportName)
302             : module(module), exportName(exportName) {}
303         ExecutableCompilationUnit *module = nullptr;
304         QV4::String *exportName = nullptr;
305     };
306 
307     ExecutableCompilationUnit();
308     ExecutableCompilationUnit(CompiledData::CompilationUnit &&compilationUnit);
309     ~ExecutableCompilationUnit();
310 
311     const Value *resolveExportRecursively(QV4::String *exportName,
312                                           QVector<ResolveSetEntry> *resolveSet);
313 
urlAt(int index)314     QUrl urlAt(int index) const { return QUrl(stringAt(index)); }
315 
316     Q_NEVER_INLINE IdentifierHash createNamedObjectsPerComponent(int componentObjectIndex);
317     const CompiledData::ExportEntry *lookupNameInExportTable(
318             const CompiledData::ExportEntry *firstExportEntry, int tableSize,
319             QV4::String *name) const;
320 
321     void getExportedNamesRecursively(
322             QStringList *names, QVector<const ExecutableCompilationUnit *> *exportNameSet,
323             bool includeDefaultExport = true) const;
324 };
325 
326 struct ResolvedTypeReference
327 {
328 public:
ResolvedTypeReferenceResolvedTypeReference329     ResolvedTypeReference()
330         : m_compilationUnit(nullptr)
331         , m_stronglyReferencesCompilationUnit(true)
332         , majorVersion(0)
333         , minorVersion(0)
334         , isFullyDynamicType(false)
335     {}
336 
~ResolvedTypeReferenceResolvedTypeReference337     ~ResolvedTypeReference()
338     {
339         if (m_stronglyReferencesCompilationUnit && m_compilationUnit)
340             m_compilationUnit->release();
341     }
342 
compilationUnitResolvedTypeReference343     QQmlRefPointer<QV4::ExecutableCompilationUnit> compilationUnit() { return m_compilationUnit; }
setCompilationUnitResolvedTypeReference344     void setCompilationUnit(QQmlRefPointer<QV4::ExecutableCompilationUnit> unit)
345     {
346         if (m_compilationUnit == unit.data())
347             return;
348         if (m_stronglyReferencesCompilationUnit) {
349             if (m_compilationUnit)
350                 m_compilationUnit->release();
351             m_compilationUnit = unit.take();
352         } else {
353             m_compilationUnit = unit.data();
354         }
355     }
356 
referencesCompilationUnitResolvedTypeReference357     bool referencesCompilationUnit() const { return m_stronglyReferencesCompilationUnit; }
setReferencesCompilationUnitResolvedTypeReference358     void setReferencesCompilationUnit(bool doReference)
359     {
360         if (doReference == m_stronglyReferencesCompilationUnit)
361             return;
362         m_stronglyReferencesCompilationUnit = doReference;
363         if (!m_compilationUnit)
364             return;
365         if (doReference) {
366             m_compilationUnit->addref();
367         } else if (m_compilationUnit->count() == 1) {
368             m_compilationUnit->release();
369             m_compilationUnit = nullptr;
370         } else {
371             m_compilationUnit->release();
372         }
373     }
374 
375     QQmlRefPointer<QQmlPropertyCache> propertyCache() const;
376     QQmlRefPointer<QQmlPropertyCache> createPropertyCache(QQmlEngine *);
377     bool addToHash(QCryptographicHash *hash, QQmlEngine *engine);
378 
379     void doDynamicTypeCheck();
380 
381     QQmlType type;
382     QQmlRefPointer<QQmlPropertyCache> typePropertyCache;
383 private:
384     Q_DISABLE_COPY_MOVE(ResolvedTypeReference)
385 
386     QV4::ExecutableCompilationUnit *m_compilationUnit;
387     bool m_stronglyReferencesCompilationUnit;
388 
389 public:
390     int majorVersion;
391     int minorVersion;
392     // Types such as QQmlPropertyMap can add properties dynamically at run-time and
393     // therefore cannot have a property cache installed when instantiated.
394     bool isFullyDynamicType;
395 };
396 
namedObjectsPerComponent(int componentObjectIndex)397 IdentifierHash ExecutableCompilationUnit::namedObjectsPerComponent(int componentObjectIndex)
398 {
399     auto it = namedObjectsPerComponentCache.find(componentObjectIndex);
400     if (Q_UNLIKELY(it == namedObjectsPerComponentCache.end()))
401         return createNamedObjectsPerComponent(componentObjectIndex);
402     return *it;
403 }
404 
405 } // namespace QV4
406 
407 QT_END_NAMESPACE
408 
409 #endif // QV4EXECUTABLECOMPILATIONUNIT_P_H
410