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 | #ifndef QV4COMPILEDDATA_P_H |
40 | #define QV4COMPILEDDATA_P_H |
41 | |
42 | // |
43 | // W A R N I N G |
44 | // ------------- |
45 | // |
46 | // This file is not part of the Qt API. It exists purely as an |
47 | // implementation detail. This header file may change from version to |
48 | // version without notice, or even be removed. |
49 | // |
50 | // We mean it. |
51 | // |
52 | |
53 | #include <functional> |
54 | |
55 | #include <QtCore/qstring.h> |
56 | #include <QtCore/qscopeguard.h> |
57 | #include <QtCore/qvector.h> |
58 | #include <QtCore/qstringlist.h> |
59 | #include <QtCore/qhash.h> |
60 | |
61 | #if QT_CONFIG(temporaryfile) |
62 | #include <QtCore/qsavefile.h> |
63 | #endif |
64 | |
65 | #include <private/qendian_p.h> |
66 | #include <private/qv4staticvalue_p.h> |
67 | #include <functional> |
68 | |
69 | QT_BEGIN_NAMESPACE |
70 | |
71 | // Bump this whenever the compiler data structures change in an incompatible way. |
72 | // |
73 | // IMPORTANT: |
74 | // |
75 | // Also change the comment behind the number to describe the latest change. This has the added |
76 | // benefit that if another patch changes the version too, it will result in a merge conflict, and |
77 | // not get removed silently. |
78 | #define QV4_DATA_STRUCTURE_VERSION 0x29// support additional required property features |
79 | |
80 | class QIODevice; |
81 | class QQmlTypeNameCache; |
82 | class QQmlType; |
83 | class QQmlEngine; |
84 | |
85 | namespace QmlIR { |
86 | struct Document; |
87 | } |
88 | |
89 | namespace QV4 { |
90 | namespace Heap { |
91 | struct Module; |
92 | struct String; |
93 | struct InternalClass; |
94 | }; |
95 | |
96 | struct Function; |
97 | class EvalISelFactory; |
98 | |
99 | namespace CompiledData { |
100 | |
101 | struct String; |
102 | struct Function; |
103 | struct Lookup; |
104 | struct RegExp; |
105 | struct Unit; |
106 | |
107 | template <typename ItemType, typename Container, const ItemType *(Container::*IndexedGetter)(int index) const> |
108 | struct TableIterator |
109 | { |
110 | TableIterator(const Container *container, int index) : container(container), index(index) {} |
111 | const Container *container; |
112 | int index; |
113 | |
114 | const ItemType *operator->() { return (container->*IndexedGetter)(index); } |
115 | ItemType operator*() {return *operator->();} |
116 | void operator++() { ++index; } |
117 | bool operator==(const TableIterator &rhs) const { return index == rhs.index; } |
118 | bool operator!=(const TableIterator &rhs) const { return index != rhs.index; } |
119 | }; |
120 | |
121 | struct Location |
122 | { |
123 | union { |
124 | quint32 _dummy; |
125 | quint32_le_bitfield<0, 20> line; |
126 | quint32_le_bitfield<20, 12> column; |
127 | }; |
128 | |
129 | Location() : _dummy(0) { } |
130 | |
131 | inline bool operator<(const Location &other) const { |
132 | return line < other.line || |
133 | (line == other.line && column < other.column); |
134 | } |
135 | }; |
136 | static_assert(sizeof(Location) == 4, "Location structure needs to have the expected size to be binary compatible on disk when generated by host compiler and loaded by target" ); |
137 | |
138 | struct RegExp |
139 | { |
140 | enum Flags : unsigned int { |
141 | RegExp_NoFlags = 0x0, |
142 | RegExp_Global = 0x01, |
143 | RegExp_IgnoreCase = 0x02, |
144 | RegExp_Multiline = 0x04, |
145 | RegExp_Unicode = 0x08, |
146 | RegExp_Sticky = 0x10 |
147 | }; |
148 | union { |
149 | quint32 _dummy; |
150 | quint32_le_bitfield<0, 5> flags; |
151 | quint32_le_bitfield<5, 27> stringIndex; |
152 | }; |
153 | |
154 | RegExp() : _dummy(0) { } |
155 | }; |
156 | static_assert(sizeof(RegExp) == 4, "RegExp structure needs to have the expected size to be binary compatible on disk when generated by host compiler and loaded by target" ); |
157 | |
158 | struct Lookup |
159 | { |
160 | enum Type : unsigned int { |
161 | Type_Getter = 0, |
162 | Type_Setter = 1, |
163 | Type_GlobalGetter = 2, |
164 | Type_QmlContextPropertyGetter = 3 |
165 | }; |
166 | |
167 | union { |
168 | quint32 _dummy; |
169 | quint32_le_bitfield<0, 4> type_and_flags; |
170 | quint32_le_bitfield<4, 28> nameIndex; |
171 | }; |
172 | |
173 | Lookup() : _dummy(0) { } |
174 | }; |
175 | static_assert(sizeof(Lookup) == 4, "Lookup structure needs to have the expected size to be binary compatible on disk when generated by host compiler and loaded by target" ); |
176 | |
177 | struct JSClassMember |
178 | { |
179 | union { |
180 | quint32 _dummy; |
181 | quint32_le_bitfield<0, 31> nameOffset; |
182 | quint32_le_bitfield<31, 1> isAccessor; |
183 | }; |
184 | |
185 | JSClassMember() : _dummy(0) { } |
186 | }; |
187 | static_assert(sizeof(JSClassMember) == 4, "JSClassMember structure needs to have the expected size to be binary compatible on disk when generated by host compiler and loaded by target" ); |
188 | |
189 | struct JSClass |
190 | { |
191 | quint32_le nMembers; |
192 | // JSClassMember[nMembers] |
193 | |
194 | static int calculateSize(int nMembers) { return (sizeof(JSClass) + nMembers * sizeof(JSClassMember) + 7) & ~7; } |
195 | }; |
196 | static_assert(sizeof(JSClass) == 4, "JSClass structure needs to have the expected size to be binary compatible on disk when generated by host compiler and loaded by target" ); |
197 | |
198 | // This data structure is intended to be binary compatible with QStringData/QStaticStringData on |
199 | // 64-bit and 32-bit little-endian architectures, in all directions. So the same structure mapped |
200 | // from a file must be castable to a QStringData regardless of the pointer size. With the first |
201 | // few fields that's easy, they're always 32-bit. However the offset field of QArrayData is a |
202 | // ptrdiff_t and thus variable in size. |
203 | // On 64-bit systems compilers enforce an 8-byte alignment and thus place it at offset 16, while |
204 | // on 32-bit systems offset 12 is sufficient. Therefore the two values don't overlap and contain |
205 | // the same value. |
206 | struct String |
207 | { |
208 | qint32_le refcount; // -1 |
209 | qint32_le size; |
210 | quint32_le allocAndCapacityReservedFlag; // 0 |
211 | quint32_le offsetOn32Bit; |
212 | quint64_le offsetOn64Bit; |
213 | // uint16 strdata[] |
214 | |
215 | static int calculateSize(const QString &str) { |
216 | return (sizeof(String) + (str.length() + 1) * sizeof(quint16) + 7) & ~0x7; |
217 | } |
218 | }; |
219 | static_assert(sizeof(String) == 24, "String structure needs to have the expected size to be binary compatible on disk when generated by host compiler and loaded by target" ); |
220 | |
221 | // Ensure compatibility with QString |
222 | static_assert(offsetof(QArrayData, ref) == offsetof(String, refcount), "refcount must be at the same location" ); |
223 | static_assert(offsetof(QArrayData, size) == offsetof(String, size), "size must be at the same location" ); |
224 | static_assert(offsetof(String, offsetOn64Bit) == 16, "offset must be at 8-byte aligned location" ); |
225 | static_assert(offsetof(String, offsetOn32Bit) == 12, "offset must be at 4-byte aligned location" ); |
226 | #if QT_POINTER_SIZE == 8 |
227 | static_assert(offsetof(QArrayData, offset) == offsetof(String, offsetOn64Bit), "offset must be at the same location" ); |
228 | #else |
229 | static_assert(offsetof(QArrayData, offset) == offsetof(String, offsetOn32Bit), "offset must be at the same location" ); |
230 | #endif |
231 | |
232 | struct CodeOffsetToLine { |
233 | quint32_le codeOffset; |
234 | quint32_le line; |
235 | }; |
236 | static_assert(sizeof(CodeOffsetToLine) == 8, "CodeOffsetToLine structure needs to have the expected size to be binary compatible on disk when generated by host compiler and loaded by target" ); |
237 | |
238 | struct Block |
239 | { |
240 | quint32_le nLocals; |
241 | quint32_le localsOffset; |
242 | quint16_le sizeOfLocalTemporalDeadZone; |
243 | quint16_le padding; |
244 | |
245 | const quint32_le *localsTable() const { return reinterpret_cast<const quint32_le *>(reinterpret_cast<const char *>(this) + localsOffset); } |
246 | |
247 | static int calculateSize(int nLocals) { |
248 | int trailingData = nLocals*sizeof (quint32); |
249 | size_t size = align(a: align(a: sizeof(Block)) + size_t(trailingData)); |
250 | Q_ASSERT(size < INT_MAX); |
251 | return int(size); |
252 | } |
253 | |
254 | static size_t align(size_t a) { |
255 | return (a + 7) & ~size_t(7); |
256 | } |
257 | }; |
258 | static_assert(sizeof(Block) == 12, "Block structure needs to have the expected size to be binary compatible on disk when generated by host compiler and loaded by target" ); |
259 | |
260 | enum class BuiltinType : unsigned int { |
261 | Var = 0, Variant, Int, Bool, Real, String, Url, Color, |
262 | Font, Time, Date, DateTime, Rect, Point, Size, |
263 | Vector2D, Vector3D, Vector4D, Matrix4x4, Quaternion, InvalidBuiltin |
264 | }; |
265 | |
266 | struct ParameterType |
267 | { |
268 | union { |
269 | quint32 _dummy; |
270 | quint32_le_bitfield<0, 1> indexIsBuiltinType; |
271 | quint32_le_bitfield<1, 31> typeNameIndexOrBuiltinType; |
272 | }; |
273 | }; |
274 | static_assert(sizeof(ParameterType) == 4, "ParameterType structure needs to have the expected size to be binary compatible on disk when generated by host compiler and loaded by target" ); |
275 | |
276 | struct Parameter |
277 | { |
278 | quint32_le nameIndex; |
279 | ParameterType type; |
280 | }; |
281 | static_assert(sizeof(Parameter) == 8, "Parameter structure needs to have the expected size to be binary compatible on disk when generated by host compiler and loaded by target" ); |
282 | |
283 | // Function is aligned on an 8-byte boundary to make sure there are no bus errors or penalties |
284 | // for unaligned access. The ordering of the fields is also from largest to smallest. |
285 | struct Function |
286 | { |
287 | enum Flags : unsigned int { |
288 | IsStrict = 0x1, |
289 | IsArrowFunction = 0x2, |
290 | IsGenerator = 0x4 |
291 | }; |
292 | |
293 | // Absolute offset into file where the code for this function is located. |
294 | quint32_le codeOffset; |
295 | quint32_le codeSize; |
296 | |
297 | quint32_le nameIndex; |
298 | quint16_le length; |
299 | quint16_le nFormals; |
300 | quint32_le formalsOffset; // Can't turn this into a calculated offset because of the mutation in CompilationUnit::createUnitData. |
301 | ParameterType returnType; |
302 | quint32_le localsOffset; |
303 | quint16_le nLocals; |
304 | quint16_le nLineNumbers; |
305 | size_t lineNumberOffset() const { return localsOffset + nLocals * sizeof(quint32); } |
306 | quint32_le nestedFunctionIndex; // for functions that only return a single closure, used in signal handlers |
307 | |
308 | quint32_le nRegisters; |
309 | Location location; |
310 | quint32_le nLabelInfos; |
311 | |
312 | quint16_le sizeOfLocalTemporalDeadZone; |
313 | quint16_le firstTemporalDeadZoneRegister; |
314 | quint16_le sizeOfRegisterTemporalDeadZone; |
315 | |
316 | size_t labelInfosOffset() const { return lineNumberOffset() + nLineNumbers * sizeof(CodeOffsetToLine); } |
317 | |
318 | // Keep all unaligned data at the end |
319 | quint8 flags; |
320 | quint8 padding1; |
321 | |
322 | // quint32 formalsIndex[nFormals] |
323 | // quint32 localsIndex[nLocals] |
324 | |
325 | const Parameter *formalsTable() const { return reinterpret_cast<const Parameter *>(reinterpret_cast<const char *>(this) + formalsOffset); } |
326 | const quint32_le *localsTable() const { return reinterpret_cast<const quint32_le *>(reinterpret_cast<const char *>(this) + localsOffset); } |
327 | const CodeOffsetToLine *lineNumberTable() const { return reinterpret_cast<const CodeOffsetToLine *>(reinterpret_cast<const char *>(this) + lineNumberOffset()); } |
328 | |
329 | // --- QQmlPropertyCacheCreator interface |
330 | const Parameter *formalsBegin() const { return formalsTable(); } |
331 | const Parameter *formalsEnd() const { return formalsTable() + nFormals; } |
332 | // --- |
333 | |
334 | const quint32_le *labelInfoTable() const { return reinterpret_cast<const quint32_le *>(reinterpret_cast<const char *>(this) + labelInfosOffset()); } |
335 | |
336 | const char *code() const { return reinterpret_cast<const char *>(this) + codeOffset; } |
337 | |
338 | static int calculateSize(int nFormals, int nLocals, int nLines, int nInnerfunctions, int labelInfoSize, int codeSize) { |
339 | int trailingData = nFormals * sizeof(Parameter) + (nLocals + nInnerfunctions + labelInfoSize)*sizeof (quint32) |
340 | + nLines*sizeof(CodeOffsetToLine); |
341 | size_t size = align(a: align(a: sizeof(Function)) + size_t(trailingData)) + align(a: codeSize); |
342 | Q_ASSERT(size < INT_MAX); |
343 | return int(size); |
344 | } |
345 | |
346 | static size_t align(size_t a) { |
347 | return (a + 7) & ~size_t(7); |
348 | } |
349 | }; |
350 | static_assert(sizeof(Function) == 56, "Function structure needs to have the expected size to be binary compatible on disk when generated by host compiler and loaded by target" ); |
351 | |
352 | struct Method { |
353 | enum Type { |
354 | Regular, |
355 | Getter, |
356 | Setter |
357 | }; |
358 | |
359 | quint32_le name; |
360 | quint32_le type; |
361 | quint32_le function; |
362 | }; |
363 | static_assert(sizeof(Method) == 12, "Method structure needs to have the expected size to be binary compatible on disk when generated by host compiler and loaded by target" ); |
364 | |
365 | struct Class |
366 | { |
367 | quint32_le nameIndex; |
368 | quint32_le scopeIndex; |
369 | quint32_le constructorFunction; |
370 | quint32_le nStaticMethods; |
371 | quint32_le nMethods; |
372 | quint32_le methodTableOffset; |
373 | |
374 | const Method *methodTable() const { return reinterpret_cast<const Method *>(reinterpret_cast<const char *>(this) + methodTableOffset); } |
375 | |
376 | static int calculateSize(int nStaticMethods, int nMethods) { |
377 | int trailingData = (nStaticMethods + nMethods) * sizeof(Method); |
378 | size_t size = align(a: sizeof(Class) + trailingData); |
379 | Q_ASSERT(size < INT_MAX); |
380 | return int(size); |
381 | } |
382 | |
383 | static size_t align(size_t a) { |
384 | return (a + 7) & ~size_t(7); |
385 | } |
386 | }; |
387 | static_assert(sizeof(Class) == 24, "Class structure needs to have the expected size to be binary compatible on disk when generated by host compiler and loaded by target" ); |
388 | |
389 | struct TemplateObject |
390 | { |
391 | quint32_le size; |
392 | |
393 | static int calculateSize(int size) { |
394 | int trailingData = 2 * size * sizeof(quint32_le); |
395 | size_t s = align(a: sizeof(TemplateObject) + trailingData); |
396 | Q_ASSERT(s < INT_MAX); |
397 | return int(s); |
398 | } |
399 | |
400 | static size_t align(size_t a) { |
401 | return (a + 7) & ~size_t(7); |
402 | } |
403 | |
404 | const quint32_le *stringTable() const { |
405 | return reinterpret_cast<const quint32_le *>(reinterpret_cast<const char *>(this + 1)); |
406 | } |
407 | |
408 | uint stringIndexAt(uint i) const { |
409 | return stringTable()[i]; |
410 | } |
411 | uint rawStringIndexAt(uint i) const { |
412 | return stringTable()[size + i]; |
413 | } |
414 | }; |
415 | static_assert(sizeof(TemplateObject) == 4, "Template object structure needs to have the expected size to be binary compatible on disk when generated by host compiler and loaded by target" ); |
416 | |
417 | struct ExportEntry |
418 | { |
419 | quint32_le exportName; |
420 | quint32_le moduleRequest; |
421 | quint32_le importName; |
422 | quint32_le localName; |
423 | Location location; |
424 | }; |
425 | static_assert(sizeof(ExportEntry) == 20, "ExportEntry structure needs to have the expected size to be binary compatible on disk when generated by host compiler and loaded by target" ); |
426 | |
427 | struct ImportEntry |
428 | { |
429 | quint32_le moduleRequest; |
430 | quint32_le importName; |
431 | quint32_le localName; |
432 | Location location; |
433 | }; |
434 | static_assert(sizeof(ImportEntry) == 16, "ImportEntry structure needs to have the expected size to be binary compatible on disk when generated by host compiler and loaded by target" ); |
435 | |
436 | // Qml data structures |
437 | |
438 | struct TranslationData |
439 | { |
440 | quint32_le stringIndex; |
441 | quint32_le ; |
442 | qint32_le number; |
443 | quint32_le padding; |
444 | }; |
445 | static_assert(sizeof(TranslationData) == 16, "TranslationData structure needs to have the expected size to be binary compatible on disk when generated by host compiler and loaded by target" ); |
446 | |
447 | struct Binding |
448 | { |
449 | quint32_le propertyNameIndex; |
450 | |
451 | enum ValueType : unsigned int { |
452 | Type_Invalid, |
453 | Type_Boolean, |
454 | Type_Number, |
455 | Type_String, |
456 | Type_Null, |
457 | Type_Translation, |
458 | Type_TranslationById, |
459 | Type_Script, |
460 | Type_Object, |
461 | Type_AttachedProperty, |
462 | Type_GroupProperty |
463 | }; |
464 | |
465 | enum Flags : unsigned int { |
466 | IsSignalHandlerExpression = 0x1, |
467 | IsSignalHandlerObject = 0x2, |
468 | IsOnAssignment = 0x4, |
469 | InitializerForReadOnlyDeclaration = 0x8, |
470 | IsResolvedEnum = 0x10, |
471 | IsListItem = 0x20, |
472 | IsBindingToAlias = 0x40, |
473 | IsDeferredBinding = 0x80, |
474 | IsCustomParserBinding = 0x100, |
475 | IsFunctionExpression = 0x200 |
476 | }; |
477 | |
478 | union { |
479 | quint32_le_bitfield<0, 16> flags; |
480 | quint32_le_bitfield<16, 16> type; |
481 | }; |
482 | union { |
483 | bool b; |
484 | quint32_le constantValueIndex; |
485 | quint32_le compiledScriptIndex; // used when Type_Script |
486 | quint32_le objectIndex; |
487 | quint32_le translationDataIndex; // used when Type_Translation |
488 | quint32 nullMarker; |
489 | } value; |
490 | quint32_le stringIndex; // Set for Type_String and Type_Script (the latter because of script strings) |
491 | |
492 | Location location; |
493 | Location valueLocation; |
494 | |
495 | bool isValueBinding() const |
496 | { |
497 | if (type == Type_AttachedProperty |
498 | || type == Type_GroupProperty) |
499 | return false; |
500 | if (flags & IsSignalHandlerExpression |
501 | || flags & IsSignalHandlerObject) |
502 | return false; |
503 | return true; |
504 | } |
505 | |
506 | bool isValueBindingNoAlias() const { return isValueBinding() && !(flags & IsBindingToAlias); } |
507 | bool isValueBindingToAlias() const { return isValueBinding() && (flags & IsBindingToAlias); } |
508 | |
509 | bool isSignalHandler() const |
510 | { |
511 | if (flags & IsSignalHandlerExpression || flags & IsSignalHandlerObject) { |
512 | Q_ASSERT(!isValueBinding()); |
513 | Q_ASSERT(!isAttachedProperty()); |
514 | Q_ASSERT(!isGroupProperty()); |
515 | return true; |
516 | } |
517 | return false; |
518 | } |
519 | |
520 | bool isAttachedProperty() const |
521 | { |
522 | if (type == Type_AttachedProperty) { |
523 | Q_ASSERT(!isValueBinding()); |
524 | Q_ASSERT(!isSignalHandler()); |
525 | Q_ASSERT(!isGroupProperty()); |
526 | return true; |
527 | } |
528 | return false; |
529 | } |
530 | |
531 | bool isGroupProperty() const |
532 | { |
533 | if (type == Type_GroupProperty) { |
534 | Q_ASSERT(!isValueBinding()); |
535 | Q_ASSERT(!isSignalHandler()); |
536 | Q_ASSERT(!isAttachedProperty()); |
537 | return true; |
538 | } |
539 | return false; |
540 | } |
541 | |
542 | bool isFunctionExpression() const { return (flags & IsFunctionExpression); } |
543 | |
544 | //reverse of Lexer::singleEscape() |
545 | static QString escapedString(const QString &string) |
546 | { |
547 | QString tmp = QLatin1String("\"" ); |
548 | for (int i = 0; i < string.length(); ++i) { |
549 | const QChar &c = string.at(i); |
550 | switch (c.unicode()) { |
551 | case 0x08: |
552 | tmp += QLatin1String("\\b" ); |
553 | break; |
554 | case 0x09: |
555 | tmp += QLatin1String("\\t" ); |
556 | break; |
557 | case 0x0A: |
558 | tmp += QLatin1String("\\n" ); |
559 | break; |
560 | case 0x0B: |
561 | tmp += QLatin1String("\\v" ); |
562 | break; |
563 | case 0x0C: |
564 | tmp += QLatin1String("\\f" ); |
565 | break; |
566 | case 0x0D: |
567 | tmp += QLatin1String("\\r" ); |
568 | break; |
569 | case 0x22: |
570 | tmp += QLatin1String("\\\"" ); |
571 | break; |
572 | case 0x27: |
573 | tmp += QLatin1String("\\\'" ); |
574 | break; |
575 | case 0x5C: |
576 | tmp += QLatin1String("\\\\" ); |
577 | break; |
578 | default: |
579 | tmp += c; |
580 | break; |
581 | } |
582 | } |
583 | tmp += QLatin1Char('\"'); |
584 | return tmp; |
585 | } |
586 | |
587 | bool isTranslationBinding() const { return type == Type_Translation || type == Type_TranslationById; } |
588 | bool evaluatesToString() const { return type == Type_String || isTranslationBinding(); } |
589 | |
590 | bool valueAsBoolean() const |
591 | { |
592 | if (type == Type_Boolean) |
593 | return value.b; |
594 | return false; |
595 | } |
596 | |
597 | }; |
598 | |
599 | static_assert(sizeof(Binding) == 24, "Binding structure needs to have the expected size to be binary compatible on disk when generated by host compiler and loaded by target" ); |
600 | |
601 | struct InlineComponent |
602 | { |
603 | quint32_le objectIndex; |
604 | quint32_le nameIndex; |
605 | Location location; |
606 | }; |
607 | |
608 | static_assert(sizeof(InlineComponent) == 12, "InlineComponent structure needs to have the expected size to be binary compatible on disk when generated by host compiler and loaded by target" ); |
609 | |
610 | struct EnumValue |
611 | { |
612 | quint32_le nameIndex; |
613 | qint32_le value; |
614 | Location location; |
615 | }; |
616 | static_assert(sizeof(EnumValue) == 12, "EnumValue structure needs to have the expected size to be binary compatible on disk when generated by host compiler and loaded by target" ); |
617 | |
618 | struct Enum |
619 | { |
620 | quint32_le nameIndex; |
621 | quint32_le nEnumValues; |
622 | Location location; |
623 | |
624 | const EnumValue *enumValueAt(int idx) const { |
625 | return reinterpret_cast<const EnumValue*>(this + 1) + idx; |
626 | } |
627 | |
628 | static int calculateSize(int nEnumValues) { |
629 | return (sizeof(Enum) |
630 | + nEnumValues * sizeof(EnumValue) |
631 | + 7) & ~0x7; |
632 | } |
633 | |
634 | // --- QQmlPropertyCacheCreatorInterface |
635 | const EnumValue *enumValuesBegin() const { return enumValueAt(idx: 0); } |
636 | const EnumValue *enumValuesEnd() const { return enumValueAt(idx: nEnumValues); } |
637 | int enumValueCount() const { return nEnumValues; } |
638 | // --- |
639 | }; |
640 | static_assert(sizeof(Enum) == 12, "Enum structure needs to have the expected size to be binary compatible on disk when generated by host compiler and loaded by target" ); |
641 | |
642 | struct Signal |
643 | { |
644 | quint32_le nameIndex; |
645 | quint32_le nParameters; |
646 | Location location; |
647 | // Parameter parameters[1]; |
648 | |
649 | const Parameter *parameterAt(int idx) const { |
650 | return reinterpret_cast<const Parameter*>(this + 1) + idx; |
651 | } |
652 | |
653 | static int calculateSize(int nParameters) { |
654 | return (sizeof(Signal) |
655 | + nParameters * sizeof(Parameter) |
656 | + 7) & ~0x7; |
657 | } |
658 | |
659 | // --- QQmlPropertyCacheCceatorInterface |
660 | const Parameter *parametersBegin() const { return parameterAt(idx: 0); } |
661 | const Parameter *parametersEnd() const { return parameterAt(idx: nParameters); } |
662 | int parameterCount() const { return nParameters; } |
663 | // --- |
664 | }; |
665 | static_assert(sizeof(Signal) == 12, "Signal structure needs to have the expected size to be binary compatible on disk when generated by host compiler and loaded by target" ); |
666 | |
667 | struct Property |
668 | { |
669 | quint32_le nameIndex; |
670 | union { |
671 | quint32_le_bitfield<0, 28> builtinTypeOrTypeNameIndex; |
672 | quint32_le_bitfield<28, 1> isRequired; |
673 | quint32_le_bitfield<29, 1> isBuiltinType; |
674 | quint32_le_bitfield<30, 1> isList; |
675 | quint32_le_bitfield<31, 1> isReadOnly; |
676 | }; |
677 | |
678 | Location location; |
679 | |
680 | void setBuiltinType(BuiltinType t) |
681 | { |
682 | builtinTypeOrTypeNameIndex = static_cast<quint32>(t); |
683 | isBuiltinType = true; |
684 | } |
685 | BuiltinType builtinType() const { |
686 | if (isBuiltinType) |
687 | return static_cast<BuiltinType>(quint32(builtinTypeOrTypeNameIndex)); |
688 | return BuiltinType::InvalidBuiltin; |
689 | } |
690 | void setCustomType(int nameIndex) |
691 | { |
692 | builtinTypeOrTypeNameIndex = nameIndex; |
693 | isBuiltinType = false; |
694 | } |
695 | }; |
696 | static_assert(sizeof(Property) == 12, "Property structure needs to have the expected size to be binary compatible on disk when generated by host compiler and loaded by target" ); |
697 | |
698 | struct { |
699 | quint32_le ; |
700 | }; |
701 | |
702 | static_assert (sizeof(RequiredPropertyExtraData) == 4, "RequiredPropertyExtraData structure needs to have the expected size to be binary compatible on disk when generated by host compiler and loaded by target" ); |
703 | |
704 | struct Alias { |
705 | enum Flags : unsigned int { |
706 | IsReadOnly = 0x1, |
707 | Resolved = 0x2, |
708 | AliasPointsToPointerObject = 0x4 |
709 | }; |
710 | union { |
711 | quint32_le_bitfield<0, 29> nameIndex; |
712 | quint32_le_bitfield<29, 3> flags; |
713 | }; |
714 | union { |
715 | quint32_le idIndex; // string index |
716 | quint32_le_bitfield<0, 31> targetObjectId; // object id index (in QQmlContextData::idValues) |
717 | quint32_le_bitfield<31, 1> aliasToLocalAlias; |
718 | }; |
719 | union { |
720 | quint32_le propertyNameIndex; // string index |
721 | qint32_le encodedMetaPropertyIndex; |
722 | quint32_le localAliasIndex; // index in list of aliases local to the object (if targetObjectId == objectId) |
723 | }; |
724 | Location location; |
725 | Location referenceLocation; |
726 | |
727 | bool isObjectAlias() const { |
728 | Q_ASSERT(flags & Resolved); |
729 | return encodedMetaPropertyIndex == -1; |
730 | } |
731 | }; |
732 | static_assert(sizeof(Alias) == 20, "Alias structure needs to have the expected size to be binary compatible on disk when generated by host compiler and loaded by target" ); |
733 | |
734 | struct Object |
735 | { |
736 | enum Flags : unsigned int { |
737 | NoFlag = 0x0, |
738 | IsComponent = 0x1, // object was identified to be an explicit or implicit component boundary |
739 | HasDeferredBindings = 0x2, // any of the bindings are deferred |
740 | HasCustomParserBindings = 0x4, |
741 | IsInlineComponentRoot = 0x8, |
742 | InPartOfInlineComponent = 0x10 |
743 | }; |
744 | |
745 | // Depending on the use, this may be the type name to instantiate before instantiating this |
746 | // object. For grouped properties the type name will be empty and for attached properties |
747 | // it will be the name of the attached type. |
748 | quint32_le inheritedTypeNameIndex; |
749 | quint32_le idNameIndex; |
750 | union { |
751 | quint32_le_bitfield<0, 15> flags; |
752 | quint32_le_bitfield<15, 1> defaultPropertyIsAlias; |
753 | qint32_le_bitfield<16, 16> id; |
754 | }; |
755 | qint32_le indexOfDefaultPropertyOrAlias; // -1 means no default property declared in this object |
756 | quint16_le nFunctions; |
757 | quint16_le nProperties; |
758 | quint32_le offsetToFunctions; |
759 | quint32_le offsetToProperties; |
760 | quint32_le offsetToAliases; |
761 | quint16_le nAliases; |
762 | quint16_le nEnums; |
763 | quint32_le offsetToEnums; // which in turn will be a table with offsets to variable-sized Enum objects |
764 | quint32_le offsetToSignals; // which in turn will be a table with offsets to variable-sized Signal objects |
765 | quint16_le nSignals; |
766 | quint16_le nBindings; |
767 | quint32_le offsetToBindings; |
768 | quint32_le nNamedObjectsInComponent; |
769 | quint32_le offsetToNamedObjectsInComponent; |
770 | Location location; |
771 | Location locationOfIdProperty; |
772 | quint32_le offsetToInlineComponents; |
773 | quint16_le nInlineComponents; |
774 | quint32_le ; |
775 | quint16_le ; |
776 | // Function[] |
777 | // Property[] |
778 | // Signal[] |
779 | // Binding[] |
780 | // InlineComponent[] |
781 | // RequiredPropertyExtraData[] |
782 | |
783 | static int calculateSizeExcludingSignalsAndEnums(int nFunctions, int nProperties, int nAliases, int nEnums, int nSignals, int nBindings, int nNamedObjectsInComponent, int nInlineComponents, int ) |
784 | { |
785 | return ( sizeof(Object) |
786 | + nFunctions * sizeof(quint32) |
787 | + nProperties * sizeof(Property) |
788 | + nAliases * sizeof(Alias) |
789 | + nEnums * sizeof(quint32) |
790 | + nSignals * sizeof(quint32) |
791 | + nBindings * sizeof(Binding) |
792 | + nNamedObjectsInComponent * sizeof(int) |
793 | + nInlineComponents * sizeof(InlineComponent) |
794 | + nRequiredPropertyExtraData * sizeof(RequiredPropertyExtraData) |
795 | + 0x7 |
796 | ) & ~0x7; |
797 | } |
798 | |
799 | const quint32_le *functionOffsetTable() const |
800 | { |
801 | return reinterpret_cast<const quint32_le*>(reinterpret_cast<const char *>(this) + offsetToFunctions); |
802 | } |
803 | |
804 | const Property *propertyTable() const |
805 | { |
806 | return reinterpret_cast<const Property*>(reinterpret_cast<const char *>(this) + offsetToProperties); |
807 | } |
808 | |
809 | const Alias *aliasTable() const |
810 | { |
811 | return reinterpret_cast<const Alias*>(reinterpret_cast<const char *>(this) + offsetToAliases); |
812 | } |
813 | |
814 | const Binding *bindingTable() const |
815 | { |
816 | return reinterpret_cast<const Binding*>(reinterpret_cast<const char *>(this) + offsetToBindings); |
817 | } |
818 | |
819 | const Enum *enumAt(int idx) const |
820 | { |
821 | const quint32_le *offsetTable = reinterpret_cast<const quint32_le*>((reinterpret_cast<const char *>(this)) + offsetToEnums); |
822 | const quint32_le offset = offsetTable[idx]; |
823 | return reinterpret_cast<const Enum*>(reinterpret_cast<const char*>(this) + offset); |
824 | } |
825 | |
826 | const Signal *signalAt(int idx) const |
827 | { |
828 | const quint32_le *offsetTable = reinterpret_cast<const quint32_le*>((reinterpret_cast<const char *>(this)) + offsetToSignals); |
829 | const quint32_le offset = offsetTable[idx]; |
830 | return reinterpret_cast<const Signal*>(reinterpret_cast<const char*>(this) + offset); |
831 | } |
832 | |
833 | const InlineComponent *inlineComponentAt(int idx) const |
834 | { |
835 | return inlineComponentTable() + idx; |
836 | } |
837 | |
838 | const quint32_le *namedObjectsInComponentTable() const |
839 | { |
840 | return reinterpret_cast<const quint32_le*>(reinterpret_cast<const char *>(this) + offsetToNamedObjectsInComponent); |
841 | } |
842 | |
843 | const InlineComponent *inlineComponentTable() const |
844 | { |
845 | return reinterpret_cast<const InlineComponent*>(reinterpret_cast<const char *>(this) + offsetToInlineComponents); |
846 | } |
847 | |
848 | const RequiredPropertyExtraData *(int idx) const |
849 | { |
850 | return requiredPropertyExtraDataTable() + idx; |
851 | } |
852 | |
853 | const RequiredPropertyExtraData *() const |
854 | { |
855 | return reinterpret_cast<const RequiredPropertyExtraData*>(reinterpret_cast<const char *>(this) + offsetToRequiredPropertyExtraData); |
856 | } |
857 | |
858 | // --- QQmlPropertyCacheCreator interface |
859 | int propertyCount() const { return nProperties; } |
860 | int aliasCount() const { return nAliases; } |
861 | int enumCount() const { return nEnums; } |
862 | int signalCount() const { return nSignals; } |
863 | int functionCount() const { return nFunctions; } |
864 | |
865 | const Binding *bindingsBegin() const { return bindingTable(); } |
866 | const Binding *bindingsEnd() const { return bindingTable() + nBindings; } |
867 | |
868 | const Property *propertiesBegin() const { return propertyTable(); } |
869 | const Property *propertiesEnd() const { return propertyTable() + nProperties; } |
870 | |
871 | const Alias *aliasesBegin() const { return aliasTable(); } |
872 | const Alias *aliasesEnd() const { return aliasTable() + nAliases; } |
873 | |
874 | typedef TableIterator<Enum, Object, &Object::enumAt> EnumIterator; |
875 | EnumIterator enumsBegin() const { return EnumIterator(this, 0); } |
876 | EnumIterator enumsEnd() const { return EnumIterator(this, nEnums); } |
877 | |
878 | typedef TableIterator<Signal, Object, &Object::signalAt> SignalIterator; |
879 | SignalIterator signalsBegin() const { return SignalIterator(this, 0); } |
880 | SignalIterator signalsEnd() const { return SignalIterator(this, nSignals); } |
881 | |
882 | typedef TableIterator<InlineComponent, Object, &Object::inlineComponentAt> InlineComponentIterator; |
883 | InlineComponentIterator inlineComponentsBegin() const {return InlineComponentIterator(this, 0);} |
884 | InlineComponentIterator inlineComponentsEnd() const {return InlineComponentIterator(this, nInlineComponents);} |
885 | |
886 | typedef TableIterator<RequiredPropertyExtraData, Object, &Object::requiredPropertyExtraDataAt> ; |
887 | RequiredPropertyExtraDataIterator () const {return RequiredPropertyExtraDataIterator(this, 0); }; |
888 | RequiredPropertyExtraDataIterator () const {return RequiredPropertyExtraDataIterator(this, nRequiredPropertyExtraData); }; |
889 | |
890 | int namedObjectsInComponentCount() const { return nNamedObjectsInComponent; } |
891 | // --- |
892 | }; |
893 | static_assert(sizeof(Object) == 84, "Object structure needs to have the expected size to be binary compatible on disk when generated by host compiler and loaded by target" ); |
894 | |
895 | struct Import |
896 | { |
897 | enum ImportType : unsigned int { |
898 | ImportLibrary = 0x1, |
899 | ImportFile = 0x2, |
900 | ImportScript = 0x3, |
901 | ImportInlineComponent = 0x4 |
902 | }; |
903 | quint32_le type; |
904 | |
905 | quint32_le uriIndex; |
906 | quint32_le qualifierIndex; |
907 | |
908 | qint32_le majorVersion; |
909 | qint32_le minorVersion; |
910 | |
911 | Location location; |
912 | |
913 | Import() { type = 0; uriIndex = 0; qualifierIndex = 0; majorVersion = 0; minorVersion = 0; } |
914 | }; |
915 | static_assert(sizeof(Import) == 24, "Import structure needs to have the expected size to be binary compatible on disk when generated by host compiler and loaded by target" ); |
916 | |
917 | struct QmlUnit |
918 | { |
919 | quint32_le nImports; |
920 | quint32_le offsetToImports; |
921 | quint32_le nObjects; |
922 | quint32_le offsetToObjects; |
923 | |
924 | const Import *importAt(int idx) const { |
925 | return reinterpret_cast<const Import*>((reinterpret_cast<const char *>(this)) + offsetToImports + idx * sizeof(Import)); |
926 | } |
927 | |
928 | const Object *objectAt(int idx) const { |
929 | const quint32_le *offsetTable = reinterpret_cast<const quint32_le*>((reinterpret_cast<const char *>(this)) + offsetToObjects); |
930 | const quint32_le offset = offsetTable[idx]; |
931 | return reinterpret_cast<const Object*>(reinterpret_cast<const char*>(this) + offset); |
932 | } |
933 | }; |
934 | static_assert(sizeof(QmlUnit) == 16, "QmlUnit structure needs to have the expected size to be binary compatible on disk when generated by host compiler and loaded by target" ); |
935 | |
936 | enum { QmlCompileHashSpace = 48 }; |
937 | static const char magic_str[] = "qv4cdata" ; |
938 | |
939 | struct Unit |
940 | { |
941 | // DO NOT CHANGE THESE FIELDS EVER |
942 | char magic[8]; |
943 | quint32_le version; |
944 | quint32_le qtVersion; |
945 | qint64_le sourceTimeStamp; |
946 | quint32_le unitSize; // Size of the Unit and any depending data. |
947 | // END DO NOT CHANGE THESE FIELDS EVER |
948 | |
949 | char libraryVersionHash[QmlCompileHashSpace]; |
950 | |
951 | char md5Checksum[16]; // checksum of all bytes following this field. |
952 | char dependencyMD5Checksum[16]; |
953 | |
954 | enum : unsigned int { |
955 | IsJavascript = 0x1, |
956 | StaticData = 0x2, // Unit data persistent in memory? |
957 | IsSingleton = 0x4, |
958 | IsSharedLibrary = 0x8, // .pragma shared? |
959 | IsESModule = 0x10, |
960 | PendingTypeCompilation = 0x20 // the QML data structures present are incomplete and require type compilation |
961 | }; |
962 | quint32_le flags; |
963 | quint32_le stringTableSize; |
964 | quint32_le offsetToStringTable; |
965 | quint32_le functionTableSize; |
966 | quint32_le offsetToFunctionTable; |
967 | quint32_le classTableSize; |
968 | quint32_le offsetToClassTable; |
969 | quint32_le templateObjectTableSize; |
970 | quint32_le offsetToTemplateObjectTable; |
971 | quint32_le blockTableSize; |
972 | quint32_le offsetToBlockTable; |
973 | quint32_le lookupTableSize; |
974 | quint32_le offsetToLookupTable; |
975 | quint32_le regexpTableSize; |
976 | quint32_le offsetToRegexpTable; |
977 | quint32_le constantTableSize; |
978 | quint32_le offsetToConstantTable; |
979 | quint32_le jsClassTableSize; |
980 | quint32_le offsetToJSClassTable; |
981 | quint32_le translationTableSize; |
982 | quint32_le offsetToTranslationTable; |
983 | quint32_le localExportEntryTableSize; |
984 | quint32_le offsetToLocalExportEntryTable; |
985 | quint32_le indirectExportEntryTableSize; |
986 | quint32_le offsetToIndirectExportEntryTable; |
987 | quint32_le starExportEntryTableSize; |
988 | quint32_le offsetToStarExportEntryTable; |
989 | quint32_le importEntryTableSize; |
990 | quint32_le offsetToImportEntryTable; |
991 | quint32_le moduleRequestTableSize; |
992 | quint32_le offsetToModuleRequestTable; |
993 | qint32_le indexOfRootFunction; |
994 | quint32_le sourceFileIndex; |
995 | quint32_le finalUrlIndex; |
996 | |
997 | quint32_le offsetToQmlUnit; |
998 | |
999 | /* QML specific fields */ |
1000 | |
1001 | const QmlUnit *qmlUnit() const { |
1002 | return reinterpret_cast<const QmlUnit *>(reinterpret_cast<const char *>(this) + offsetToQmlUnit); |
1003 | } |
1004 | |
1005 | QmlUnit *qmlUnit() { |
1006 | return reinterpret_cast<QmlUnit *>(reinterpret_cast<char *>(this) + offsetToQmlUnit); |
1007 | } |
1008 | |
1009 | bool isSingleton() const { |
1010 | return flags & Unit::IsSingleton; |
1011 | } |
1012 | /* end QML specific fields*/ |
1013 | |
1014 | QString stringAtInternal(int idx) const { |
1015 | Q_ASSERT(idx < int(stringTableSize)); |
1016 | const quint32_le *offsetTable = reinterpret_cast<const quint32_le*>((reinterpret_cast<const char *>(this)) + offsetToStringTable); |
1017 | const quint32_le offset = offsetTable[idx]; |
1018 | const String *str = reinterpret_cast<const String*>(reinterpret_cast<const char *>(this) + offset); |
1019 | if (str->size == 0) |
1020 | return QString(); |
1021 | #if Q_BYTE_ORDER == Q_LITTLE_ENDIAN |
1022 | if (flags & StaticData) { |
1023 | const QStringDataPtr holder = { .ptr: const_cast<QStringData *>(reinterpret_cast<const QStringData*>(str)) }; |
1024 | return QString(holder); |
1025 | } |
1026 | const QChar *characters = reinterpret_cast<const QChar *>(str + 1); |
1027 | return QString(characters, str->size); |
1028 | #else |
1029 | const quint16_le *characters = reinterpret_cast<const quint16_le *>(str + 1); |
1030 | QString qstr(str->size, Qt::Uninitialized); |
1031 | QChar *ch = qstr.data(); |
1032 | for (int i = 0; i < str->size; ++i) |
1033 | ch[i] = QChar(characters[i]); |
1034 | return qstr; |
1035 | #endif |
1036 | } |
1037 | |
1038 | const quint32_le *functionOffsetTable() const { return reinterpret_cast<const quint32_le*>((reinterpret_cast<const char *>(this)) + offsetToFunctionTable); } |
1039 | const quint32_le *classOffsetTable() const { return reinterpret_cast<const quint32_le*>((reinterpret_cast<const char *>(this)) + offsetToClassTable); } |
1040 | const quint32_le *templateObjectOffsetTable() const { return reinterpret_cast<const quint32_le*>((reinterpret_cast<const char *>(this)) + offsetToTemplateObjectTable); } |
1041 | const quint32_le *blockOffsetTable() const { return reinterpret_cast<const quint32_le*>((reinterpret_cast<const char *>(this)) + offsetToBlockTable); } |
1042 | |
1043 | const Function *functionAt(int idx) const { |
1044 | const quint32_le *offsetTable = functionOffsetTable(); |
1045 | const quint32_le offset = offsetTable[idx]; |
1046 | return reinterpret_cast<const Function*>(reinterpret_cast<const char *>(this) + offset); |
1047 | } |
1048 | |
1049 | const Class *classAt(int idx) const { |
1050 | const quint32_le *offsetTable = classOffsetTable(); |
1051 | const quint32_le offset = offsetTable[idx]; |
1052 | return reinterpret_cast<const Class *>(reinterpret_cast<const char *>(this) + offset); |
1053 | } |
1054 | |
1055 | const TemplateObject *templateObjectAt(int idx) const { |
1056 | const quint32_le *offsetTable = templateObjectOffsetTable(); |
1057 | const quint32_le offset = offsetTable[idx]; |
1058 | return reinterpret_cast<const TemplateObject *>(reinterpret_cast<const char *>(this) + offset); |
1059 | } |
1060 | |
1061 | const Block *blockAt(int idx) const { |
1062 | const quint32_le *offsetTable = blockOffsetTable(); |
1063 | const quint32_le offset = offsetTable[idx]; |
1064 | return reinterpret_cast<const Block *>(reinterpret_cast<const char *>(this) + offset); |
1065 | } |
1066 | |
1067 | const Lookup *lookupTable() const { return reinterpret_cast<const Lookup*>(reinterpret_cast<const char *>(this) + offsetToLookupTable); } |
1068 | const RegExp *regexpAt(int index) const { |
1069 | return reinterpret_cast<const RegExp*>(reinterpret_cast<const char *>(this) + offsetToRegexpTable + index * sizeof(RegExp)); |
1070 | } |
1071 | const quint64_le *constants() const { |
1072 | return reinterpret_cast<const quint64_le*>(reinterpret_cast<const char *>(this) + offsetToConstantTable); |
1073 | } |
1074 | |
1075 | const JSClassMember *jsClassAt(int idx, int *nMembers) const { |
1076 | const quint32_le *offsetTable = reinterpret_cast<const quint32_le *>(reinterpret_cast<const char *>(this) + offsetToJSClassTable); |
1077 | const quint32_le offset = offsetTable[idx]; |
1078 | const char *ptr = reinterpret_cast<const char *>(this) + offset; |
1079 | const JSClass *klass = reinterpret_cast<const JSClass *>(ptr); |
1080 | *nMembers = klass->nMembers; |
1081 | return reinterpret_cast<const JSClassMember*>(ptr + sizeof(JSClass)); |
1082 | } |
1083 | |
1084 | const TranslationData *translations() const { |
1085 | return reinterpret_cast<const TranslationData *>(reinterpret_cast<const char *>(this) + offsetToTranslationTable); |
1086 | } |
1087 | |
1088 | const ImportEntry *importEntryTable() const { return reinterpret_cast<const ImportEntry *>(reinterpret_cast<const char *>(this) + offsetToImportEntryTable); } |
1089 | const ExportEntry *localExportEntryTable() const { return reinterpret_cast<const ExportEntry *>(reinterpret_cast<const char *>(this) + offsetToLocalExportEntryTable); } |
1090 | const ExportEntry *indirectExportEntryTable() const { return reinterpret_cast<const ExportEntry *>(reinterpret_cast<const char *>(this) + offsetToIndirectExportEntryTable); } |
1091 | const ExportEntry *starExportEntryTable() const { return reinterpret_cast<const ExportEntry *>(reinterpret_cast<const char *>(this) + offsetToStarExportEntryTable); } |
1092 | |
1093 | const quint32_le *moduleRequestTable() const { return reinterpret_cast<const quint32_le*>((reinterpret_cast<const char *>(this)) + offsetToModuleRequestTable); } |
1094 | }; |
1095 | |
1096 | static_assert(sizeof(Unit) == 248, "Unit structure needs to have the expected size to be binary compatible on disk when generated by host compiler and loaded by target" ); |
1097 | |
1098 | struct TypeReference |
1099 | { |
1100 | TypeReference(const Location &loc) |
1101 | : location(loc) |
1102 | , needsCreation(false) |
1103 | , errorWhenNotFound(false) |
1104 | {} |
1105 | Location location; // first use |
1106 | bool needsCreation : 1; // whether the type needs to be creatable or not |
1107 | bool errorWhenNotFound: 1; |
1108 | }; |
1109 | |
1110 | // Map from name index to location of first use. |
1111 | struct TypeReferenceMap : QHash<int, TypeReference> |
1112 | { |
1113 | TypeReference &add(int nameIndex, const Location &loc) { |
1114 | Iterator it = find(key: nameIndex); |
1115 | if (it != end()) |
1116 | return *it; |
1117 | return *insert(key: nameIndex, value: loc); |
1118 | } |
1119 | |
1120 | template <typename CompiledObject> |
1121 | void collectFromObject(const CompiledObject *obj) |
1122 | { |
1123 | if (obj->inheritedTypeNameIndex != 0) { |
1124 | TypeReference &r = this->add(nameIndex: obj->inheritedTypeNameIndex, loc: obj->location); |
1125 | r.needsCreation = true; |
1126 | r.errorWhenNotFound = true; |
1127 | } |
1128 | |
1129 | auto prop = obj->propertiesBegin(); |
1130 | auto const propEnd = obj->propertiesEnd(); |
1131 | for ( ; prop != propEnd; ++prop) { |
1132 | if (!prop->isBuiltinType) { |
1133 | TypeReference &r = this->add(nameIndex: prop->builtinTypeOrTypeNameIndex, loc: prop->location); |
1134 | r.errorWhenNotFound = true; |
1135 | } |
1136 | } |
1137 | |
1138 | auto binding = obj->bindingsBegin(); |
1139 | auto const bindingEnd = obj->bindingsEnd(); |
1140 | for ( ; binding != bindingEnd; ++binding) { |
1141 | if (binding->type == QV4::CompiledData::Binding::Type_AttachedProperty) |
1142 | this->add(nameIndex: binding->propertyNameIndex, loc: binding->location); |
1143 | } |
1144 | |
1145 | auto ic = obj->inlineComponentsBegin(); |
1146 | auto const icEnd = obj->inlineComponentsEnd(); |
1147 | for (; ic != icEnd; ++ic) { |
1148 | this->add(nameIndex: ic->nameIndex, loc: ic->location); |
1149 | } |
1150 | } |
1151 | |
1152 | template <typename Iterator> |
1153 | void collectFromObjects(Iterator it, Iterator end) |
1154 | { |
1155 | for (; it != end; ++it) |
1156 | collectFromObject(*it); |
1157 | } |
1158 | }; |
1159 | |
1160 | using DependentTypesHasher = std::function<QByteArray()>; |
1161 | |
1162 | // This is how this hooks into the existing structures: |
1163 | |
1164 | struct CompilationUnitBase |
1165 | { |
1166 | Q_DISABLE_COPY(CompilationUnitBase) |
1167 | |
1168 | CompilationUnitBase() = default; |
1169 | ~CompilationUnitBase() = default; |
1170 | |
1171 | CompilationUnitBase(CompilationUnitBase &&other) noexcept { *this = std::move(other); } |
1172 | |
1173 | CompilationUnitBase &operator=(CompilationUnitBase &&other) noexcept |
1174 | { |
1175 | if (this != &other) { |
1176 | runtimeStrings = other.runtimeStrings; |
1177 | other.runtimeStrings = nullptr; |
1178 | constants = other.constants; |
1179 | other.constants = nullptr; |
1180 | runtimeRegularExpressions = other.runtimeRegularExpressions; |
1181 | other.runtimeRegularExpressions = nullptr; |
1182 | runtimeClasses = other.runtimeClasses; |
1183 | other.runtimeClasses = nullptr; |
1184 | imports = other.imports; |
1185 | other.imports = nullptr; |
1186 | } |
1187 | return *this; |
1188 | } |
1189 | |
1190 | // pointers either to data->constants() or little-endian memory copy. |
1191 | Heap::String **runtimeStrings = nullptr; // Array |
1192 | const StaticValue* constants = nullptr; |
1193 | QV4::StaticValue *runtimeRegularExpressions = nullptr; |
1194 | Heap::InternalClass **runtimeClasses = nullptr; |
1195 | const StaticValue** imports = nullptr; |
1196 | }; |
1197 | |
1198 | Q_STATIC_ASSERT(std::is_standard_layout<CompilationUnitBase>::value); |
1199 | Q_STATIC_ASSERT(offsetof(CompilationUnitBase, runtimeStrings) == 0); |
1200 | Q_STATIC_ASSERT(offsetof(CompilationUnitBase, constants) == sizeof(QV4::Heap::String **)); |
1201 | Q_STATIC_ASSERT(offsetof(CompilationUnitBase, runtimeRegularExpressions) == offsetof(CompilationUnitBase, constants) + sizeof(const StaticValue *)); |
1202 | Q_STATIC_ASSERT(offsetof(CompilationUnitBase, runtimeClasses) == offsetof(CompilationUnitBase, runtimeRegularExpressions) + sizeof(const StaticValue *)); |
1203 | Q_STATIC_ASSERT(offsetof(CompilationUnitBase, imports) == offsetof(CompilationUnitBase, runtimeClasses) + sizeof(const StaticValue *)); |
1204 | |
1205 | struct CompilationUnit : public CompilationUnitBase |
1206 | { |
1207 | Q_DISABLE_COPY(CompilationUnit) |
1208 | |
1209 | const Unit *data = nullptr; |
1210 | const QmlUnit *qmlData = nullptr; |
1211 | QStringList dynamicStrings; |
1212 | public: |
1213 | using CompiledObject = CompiledData::Object; |
1214 | |
1215 | CompilationUnit(const Unit *unitData = nullptr, const QString &fileName = QString(), |
1216 | const QString &finalUrlString = QString()) |
1217 | { |
1218 | setUnitData(unitData, qmlUnit: nullptr, fileName, finalUrlString); |
1219 | } |
1220 | |
1221 | ~CompilationUnit() |
1222 | { |
1223 | if (data) { |
1224 | if (data->qmlUnit() != qmlData) |
1225 | free(ptr: const_cast<QmlUnit *>(qmlData)); |
1226 | qmlData = nullptr; |
1227 | |
1228 | if (!(data->flags & QV4::CompiledData::Unit::StaticData)) |
1229 | free(ptr: const_cast<Unit *>(data)); |
1230 | } |
1231 | data = nullptr; |
1232 | #if Q_BYTE_ORDER == Q_BIG_ENDIAN |
1233 | delete [] constants; |
1234 | constants = nullptr; |
1235 | #endif |
1236 | |
1237 | delete [] imports; |
1238 | imports = nullptr; |
1239 | } |
1240 | |
1241 | CompilationUnit(CompilationUnit &&other) noexcept |
1242 | { |
1243 | *this = std::move(other); |
1244 | } |
1245 | |
1246 | CompilationUnit &operator=(CompilationUnit &&other) noexcept |
1247 | { |
1248 | if (this != &other) { |
1249 | data = other.data; |
1250 | other.data = nullptr; |
1251 | qmlData = other.qmlData; |
1252 | other.qmlData = nullptr; |
1253 | dynamicStrings = std::move(other.dynamicStrings); |
1254 | other.dynamicStrings.clear(); |
1255 | m_fileName = std::move(other.m_fileName); |
1256 | other.m_fileName.clear(); |
1257 | m_finalUrlString = std::move(other.m_finalUrlString); |
1258 | other.m_finalUrlString.clear(); |
1259 | m_module = other.m_module; |
1260 | other.m_module = nullptr; |
1261 | CompilationUnitBase::operator=(other: std::move(other)); |
1262 | } |
1263 | return *this; |
1264 | } |
1265 | |
1266 | const Unit *unitData() const { return data; } |
1267 | |
1268 | void setUnitData(const Unit *unitData, const QmlUnit *qmlUnit = nullptr, |
1269 | const QString &fileName = QString(), const QString &finalUrlString = QString()) |
1270 | { |
1271 | data = unitData; |
1272 | qmlData = nullptr; |
1273 | #if Q_BYTE_ORDER == Q_BIG_ENDIAN |
1274 | delete [] constants; |
1275 | #endif |
1276 | constants = nullptr; |
1277 | m_fileName.clear(); |
1278 | m_finalUrlString.clear(); |
1279 | if (!data) |
1280 | return; |
1281 | |
1282 | qmlData = qmlUnit ? qmlUnit : data->qmlUnit(); |
1283 | |
1284 | #if Q_BYTE_ORDER == Q_BIG_ENDIAN |
1285 | StaticValue *bigEndianConstants = new StaticValue[data->constantTableSize]; |
1286 | const quint64_le *littleEndianConstants = data->constants(); |
1287 | for (uint i = 0; i < data->constantTableSize; ++i) |
1288 | bigEndianConstants[i] = StaticValue::fromReturnedValue(littleEndianConstants[i]); |
1289 | constants = bigEndianConstants; |
1290 | #else |
1291 | constants = reinterpret_cast<const StaticValue*>(data->constants()); |
1292 | #endif |
1293 | |
1294 | m_fileName = !fileName.isEmpty() ? fileName : stringAt(index: data->sourceFileIndex); |
1295 | m_finalUrlString = !finalUrlString.isEmpty() ? finalUrlString : stringAt(index: data->finalUrlIndex); |
1296 | } |
1297 | |
1298 | QString stringAt(int index) const |
1299 | { |
1300 | if (uint(index) >= data->stringTableSize) |
1301 | return dynamicStrings.at(i: index - data->stringTableSize); |
1302 | return data->stringAtInternal(idx: index); |
1303 | } |
1304 | |
1305 | QString fileName() const { return m_fileName; } |
1306 | QString finalUrlString() const { return m_finalUrlString; } |
1307 | |
1308 | Heap::Module *module() const { return m_module; } |
1309 | void setModule(Heap::Module *module) { m_module = module; } |
1310 | |
1311 | private: |
1312 | QString m_fileName; // initialized from data->sourceFileIndex |
1313 | QString m_finalUrlString; // initialized from data->finalUrlIndex |
1314 | |
1315 | Heap::Module *m_module = nullptr; |
1316 | }; |
1317 | |
1318 | class SaveableUnitPointer |
1319 | { |
1320 | Q_DISABLE_COPY_MOVE(SaveableUnitPointer) |
1321 | public: |
1322 | SaveableUnitPointer(const Unit *unit, quint32 temporaryFlags = Unit::StaticData) : |
1323 | unit(unit), |
1324 | temporaryFlags(temporaryFlags) |
1325 | { |
1326 | } |
1327 | |
1328 | ~SaveableUnitPointer() = default; |
1329 | |
1330 | template<typename Char> |
1331 | bool saveToDisk(const std::function<bool(const Char *, quint32)> &writer) const |
1332 | { |
1333 | const quint32_le oldFlags = mutableFlags(); |
1334 | auto cleanup = qScopeGuard([this, oldFlags]() { mutableFlags() = oldFlags; }); |
1335 | mutableFlags() |= temporaryFlags; |
1336 | return writer(data<Char>(), size()); |
1337 | } |
1338 | |
1339 | static bool writeDataToFile(const QString &outputFileName, const char *data, quint32 size, |
1340 | QString *errorString) |
1341 | { |
1342 | #if QT_CONFIG(temporaryfile) |
1343 | QSaveFile cacheFile(outputFileName); |
1344 | if (!cacheFile.open(flags: QIODevice::WriteOnly | QIODevice::Truncate) |
1345 | || cacheFile.write(data, len: size) != size |
1346 | || !cacheFile.commit()) { |
1347 | *errorString = cacheFile.errorString(); |
1348 | return false; |
1349 | } |
1350 | |
1351 | errorString->clear(); |
1352 | return true; |
1353 | #else |
1354 | Q_UNUSED(outputFileName) |
1355 | *errorString = QStringLiteral("features.temporaryfile is disabled." ); |
1356 | return false; |
1357 | #endif |
1358 | } |
1359 | |
1360 | private: |
1361 | const Unit *unit; |
1362 | quint32 temporaryFlags; |
1363 | |
1364 | quint32_le &mutableFlags() const |
1365 | { |
1366 | return const_cast<Unit *>(unit)->flags; |
1367 | } |
1368 | |
1369 | template<typename Char> |
1370 | const Char *data() const |
1371 | { |
1372 | Q_STATIC_ASSERT(sizeof(Char) == 1); |
1373 | const Char *dataPtr; |
1374 | memcpy(&dataPtr, &unit, sizeof(dataPtr)); |
1375 | return dataPtr; |
1376 | } |
1377 | |
1378 | quint32 size() const |
1379 | { |
1380 | return unit->unitSize; |
1381 | } |
1382 | }; |
1383 | |
1384 | |
1385 | } // CompiledData namespace |
1386 | } // QV4 namespace |
1387 | |
1388 | Q_DECLARE_TYPEINFO(QV4::CompiledData::JSClassMember, Q_PRIMITIVE_TYPE); |
1389 | |
1390 | QT_END_NAMESPACE |
1391 | |
1392 | #endif |
1393 | |