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