1 | // Copyright (C) 2016 The Qt Company Ltd. |
2 | // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only |
3 | #ifndef QV4COMPILEDDATA_P_H |
4 | #define QV4COMPILEDDATA_P_H |
5 | |
6 | // |
7 | // W A R N I N G |
8 | // ------------- |
9 | // |
10 | // This file is not part of the Qt API. It exists purely as an |
11 | // implementation detail. This header file may change from version to |
12 | // version without notice, or even be removed. |
13 | // |
14 | // We mean it. |
15 | // |
16 | |
17 | #include <functional> |
18 | |
19 | #include <QtCore/qhashfunctions.h> |
20 | #include <QtCore/qstring.h> |
21 | #include <QtCore/qscopeguard.h> |
22 | #include <QtCore/qvector.h> |
23 | #include <QtCore/qstringlist.h> |
24 | #include <QtCore/qhash.h> |
25 | #include <QtCore/qversionnumber.h> |
26 | #include <QtCore/qlocale.h> |
27 | |
28 | #if QT_CONFIG(temporaryfile) |
29 | #include <QtCore/qsavefile.h> |
30 | #endif |
31 | |
32 | #include <private/qendian_p.h> |
33 | #include <private/qv4staticvalue_p.h> |
34 | #include <functional> |
35 | #include <limits.h> |
36 | |
37 | QT_BEGIN_NAMESPACE |
38 | |
39 | // Bump this whenever the compiler data structures change in an incompatible way. |
40 | // |
41 | // IMPORTANT: |
42 | // |
43 | // Also change the comment behind the number to describe the latest change. This has the added |
44 | // benefit that if another patch changes the version too, it will result in a merge conflict, and |
45 | // not get removed silently. |
46 | #define QV4_DATA_STRUCTURE_VERSION 0x3C // Restructured builtin type enums |
47 | |
48 | class QIODevice; |
49 | class QQmlTypeNameCache; |
50 | class QQmlType; |
51 | class QQmlEngine; |
52 | |
53 | namespace QQmlPrivate { |
54 | struct AOTCompiledFunction; |
55 | } |
56 | |
57 | namespace QmlIR { |
58 | struct Document; |
59 | } |
60 | |
61 | namespace QV4 { |
62 | namespace Heap { |
63 | struct Module; |
64 | struct String; |
65 | struct InternalClass; |
66 | }; |
67 | |
68 | struct Function; |
69 | class EvalISelFactory; |
70 | |
71 | namespace CompiledData { |
72 | |
73 | struct String; |
74 | struct Function; |
75 | struct Lookup; |
76 | struct RegExp; |
77 | struct Unit; |
78 | |
79 | template <typename ItemType, typename Container, const ItemType *(Container::*IndexedGetter)(int index) const> |
80 | struct TableIterator |
81 | { |
82 | TableIterator(const Container *container, int index) : container(container), index(index) {} |
83 | const Container *container; |
84 | int index; |
85 | |
86 | const ItemType *operator->() { return (container->*IndexedGetter)(index); } |
87 | ItemType operator*() {return *operator->();} |
88 | void operator++() { ++index; } |
89 | bool operator==(const TableIterator &rhs) const { return index == rhs.index; } |
90 | bool operator!=(const TableIterator &rhs) const { return index != rhs.index; } |
91 | }; |
92 | |
93 | struct Location |
94 | { |
95 | Location() : m_data(QSpecialIntegerBitfieldZero) {} |
96 | Location(quint32 l, quint32 c) : Location() |
97 | { |
98 | m_data.set<LineField>(l); |
99 | m_data.set<ColumnField>(c); |
100 | Q_ASSERT(m_data.get<LineField>() == l); |
101 | Q_ASSERT(m_data.get<ColumnField>() == c); |
102 | } |
103 | |
104 | inline bool operator<(const Location &other) const { |
105 | return m_data.get<LineField>() < other.m_data.get<LineField>() |
106 | || (m_data.get<LineField>() == other.m_data.get<LineField>() |
107 | && m_data.get<ColumnField>() < other.m_data.get<ColumnField>()); |
108 | } |
109 | |
110 | friend size_t qHash(const Location &location, size_t seed = 0) |
111 | { |
112 | return QT_PREPEND_NAMESPACE(qHash)(key: location.m_data.data(), seed); |
113 | } |
114 | |
115 | friend bool operator==(const Location &a, const Location &b) |
116 | { |
117 | return a.m_data.data()== b.m_data.data(); |
118 | } |
119 | |
120 | void set(quint32 line, quint32 column) |
121 | { |
122 | m_data.set<LineField>(line); |
123 | m_data.set<ColumnField>(column); |
124 | } |
125 | |
126 | quint32 line() const { return m_data.get<LineField>(); } |
127 | quint32 column() const { return m_data.get<ColumnField>(); } |
128 | |
129 | private: |
130 | using LineField = quint32_le_bitfield_member<0, 20>; |
131 | using ColumnField = quint32_le_bitfield_member<20, 12>; |
132 | |
133 | quint32_le_bitfield_union<LineField, ColumnField> m_data; |
134 | }; |
135 | 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" ); |
136 | |
137 | struct RegExp |
138 | { |
139 | enum Flags : unsigned int { |
140 | RegExp_NoFlags = 0x0, |
141 | RegExp_Global = 0x01, |
142 | RegExp_IgnoreCase = 0x02, |
143 | RegExp_Multiline = 0x04, |
144 | RegExp_Unicode = 0x08, |
145 | RegExp_Sticky = 0x10 |
146 | }; |
147 | |
148 | RegExp() : m_data(QSpecialIntegerBitfieldZero) {} |
149 | RegExp(quint32 flags, quint32 stringIndex) : RegExp() |
150 | { |
151 | m_data.set<FlagsField>(flags); |
152 | m_data.set<StringIndexField>(stringIndex); |
153 | } |
154 | |
155 | quint32 flags() const { return m_data.get<FlagsField>(); } |
156 | quint32 stringIndex() const { return m_data.get<StringIndexField>(); } |
157 | |
158 | private: |
159 | using FlagsField = quint32_le_bitfield_member<0, 5>; |
160 | using StringIndexField = quint32_le_bitfield_member<5, 27>; |
161 | quint32_le_bitfield_union<FlagsField, StringIndexField> m_data; |
162 | }; |
163 | 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" ); |
164 | |
165 | struct Lookup |
166 | { |
167 | enum Type : unsigned int { |
168 | Type_Getter = 0, |
169 | Type_Setter = 1, |
170 | Type_GlobalGetter = 2, |
171 | Type_QmlContextPropertyGetter = 3 |
172 | }; |
173 | |
174 | enum Mode : unsigned int { |
175 | Mode_ForStorage = 0, |
176 | Mode_ForCall = 1 |
177 | }; |
178 | |
179 | quint32 type() const { return m_data.get<TypeField>(); } |
180 | quint32 nameIndex() const { return m_data.get<NameIndexField>(); } |
181 | quint32 mode() const { return m_data.get<ModeField>(); } |
182 | |
183 | Lookup() : m_data(QSpecialIntegerBitfieldZero) {} |
184 | Lookup(Type type, Mode mode, quint32 nameIndex) : Lookup() |
185 | { |
186 | m_data.set<TypeField>(type); |
187 | m_data.set<ModeField>(mode); |
188 | m_data.set<NameIndexField>(nameIndex); |
189 | } |
190 | |
191 | private: |
192 | using TypeField = quint32_le_bitfield_member<0, 2>; |
193 | using ModeField = quint32_le_bitfield_member<2, 1>; |
194 | // 1 bit left |
195 | using NameIndexField = quint32_le_bitfield_member<4, 28>; |
196 | quint32_le_bitfield_union<TypeField, ModeField, NameIndexField> m_data; |
197 | }; |
198 | 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" ); |
199 | |
200 | struct JSClassMember |
201 | { |
202 | JSClassMember() : m_data(QSpecialIntegerBitfieldZero) {} |
203 | |
204 | void set(quint32 nameOffset, bool isAccessor) |
205 | { |
206 | m_data.set<NameOffsetField>(nameOffset); |
207 | m_data.set<IsAccessorField>(isAccessor ? 1 : 0); |
208 | } |
209 | |
210 | quint32 nameOffset() const { return m_data.get<NameOffsetField>(); } |
211 | bool isAccessor() const { return m_data.get<IsAccessorField>() != 0; } |
212 | |
213 | private: |
214 | using NameOffsetField = quint32_le_bitfield_member<0, 31>; |
215 | using IsAccessorField = quint32_le_bitfield_member<31, 1>; |
216 | quint32_le_bitfield_union<NameOffsetField, IsAccessorField> m_data; |
217 | }; |
218 | 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" ); |
219 | |
220 | struct JSClass |
221 | { |
222 | quint32_le nMembers; |
223 | // JSClassMember[nMembers] |
224 | |
225 | static int calculateSize(int nMembers) { return (sizeof(JSClass) + nMembers * sizeof(JSClassMember) + 7) & ~7; } |
226 | }; |
227 | 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" ); |
228 | |
229 | struct String |
230 | { |
231 | qint32_le size; |
232 | |
233 | static int calculateSize(const QString &str) { |
234 | // we cannot enconuter strings larger than INT_MAX anyway, as such a string |
235 | // would already break in other parts of the compilation process |
236 | return (sizeof(String) + (int(str.size()) + 1) * sizeof(quint16) + 7) & ~0x7; |
237 | } |
238 | }; |
239 | |
240 | static_assert (sizeof (String) == 4, "String structure needs to have the expected size to be binary compatible on disk when generated by host compiler and loaded by target" ); |
241 | |
242 | struct CodeOffsetToLineAndStatement { |
243 | quint32_le codeOffset; |
244 | qint32_le line; // signed because debug instructions get negative line numbers |
245 | quint32_le statement; |
246 | }; |
247 | static_assert(sizeof(CodeOffsetToLineAndStatement) == 12, "CodeOffsetToLineAndStatement structure needs to have the expected size to be binary compatible on disk when generated by host compiler and loaded by target" ); |
248 | |
249 | struct Block |
250 | { |
251 | quint32_le nLocals; |
252 | quint32_le localsOffset; |
253 | quint16_le sizeOfLocalTemporalDeadZone; |
254 | quint16_le padding; |
255 | |
256 | const quint32_le *localsTable() const { return reinterpret_cast<const quint32_le *>(reinterpret_cast<const char *>(this) + localsOffset); } |
257 | |
258 | static int calculateSize(int nLocals) { |
259 | int trailingData = nLocals*sizeof (quint32); |
260 | size_t size = align(a: align(a: sizeof(Block)) + size_t(trailingData)); |
261 | Q_ASSERT(size < INT_MAX); |
262 | return int(size); |
263 | } |
264 | |
265 | static size_t align(size_t a) { |
266 | return (a + 7) & ~size_t(7); |
267 | } |
268 | }; |
269 | 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" ); |
270 | |
271 | enum class NamedBuiltin: unsigned int { |
272 | Void, Var, Int, Bool, Real, String, Url, DateTime, RegExp |
273 | }; |
274 | |
275 | enum class CommonType : unsigned int { |
276 | // Actual named builtins |
277 | Void = uint(NamedBuiltin::Void), |
278 | Var = uint(NamedBuiltin::Var), |
279 | Int = uint(NamedBuiltin::Int), |
280 | Bool = uint(NamedBuiltin::Bool), |
281 | Real = uint(NamedBuiltin::Real), |
282 | String = uint(NamedBuiltin::String), |
283 | Url = uint(NamedBuiltin::Url), |
284 | DateTime = uint(NamedBuiltin::DateTime), |
285 | RegExp = uint(NamedBuiltin::RegExp), |
286 | |
287 | // Optimization for very common other types |
288 | Time, Date, Rect, Point, Size, |
289 | |
290 | // No type specified or not recognized |
291 | Invalid |
292 | }; |
293 | |
294 | struct ParameterType |
295 | { |
296 | enum Flag { |
297 | NoFlag = 0x0, |
298 | Common = 0x1, |
299 | List = 0x2, |
300 | }; |
301 | Q_DECLARE_FLAGS(Flags, Flag); |
302 | |
303 | void set(Flags flags, quint32 typeNameIndexOrCommonType) |
304 | { |
305 | m_data.set<IsListField>(flags.testFlag(flag: List) ? 1 : 0); |
306 | m_data.set<IndexIsCommonTypeField>(flags.testFlag(flag: Common) ? 1 : 0); |
307 | m_data.set<TypeNameIndexOrCommonTypeField>(typeNameIndexOrCommonType); |
308 | } |
309 | |
310 | bool indexIsCommonType() const |
311 | { |
312 | return m_data.get<IndexIsCommonTypeField>() != 0; |
313 | } |
314 | |
315 | bool isList() const |
316 | { |
317 | return m_data.get<IsListField>() != 0; |
318 | } |
319 | |
320 | quint32 typeNameIndexOrCommonType() const |
321 | { |
322 | return m_data.get<TypeNameIndexOrCommonTypeField>(); |
323 | } |
324 | |
325 | private: |
326 | using IndexIsCommonTypeField = quint32_le_bitfield_member<0, 1>; |
327 | using IsListField = quint32_le_bitfield_member<1, 1>; |
328 | using TypeNameIndexOrCommonTypeField = quint32_le_bitfield_member<2, 30>; |
329 | quint32_le_bitfield_union<IndexIsCommonTypeField, IsListField, TypeNameIndexOrCommonTypeField> m_data; |
330 | }; |
331 | 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" ); |
332 | |
333 | struct Parameter |
334 | { |
335 | quint32_le nameIndex; |
336 | ParameterType type; |
337 | }; |
338 | 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" ); |
339 | |
340 | // Function is aligned on an 8-byte boundary to make sure there are no bus errors or penalties |
341 | // for unaligned access. The ordering of the fields is also from largest to smallest. |
342 | struct Function |
343 | { |
344 | enum Flags : unsigned int { |
345 | IsStrict = 0x1, |
346 | IsArrowFunction = 0x2, |
347 | IsGenerator = 0x4, |
348 | IsClosureWrapper = 0x8, |
349 | }; |
350 | |
351 | // Absolute offset into file where the code for this function is located. |
352 | quint32_le codeOffset; |
353 | quint32_le codeSize; |
354 | |
355 | quint32_le nameIndex; |
356 | quint16_le length; |
357 | quint16_le nFormals; |
358 | quint32_le formalsOffset; // Can't turn this into a calculated offset because of the mutation in CompilationUnit::createUnitData. |
359 | ParameterType returnType; |
360 | quint32_le localsOffset; |
361 | quint16_le nLocals; |
362 | quint16_le nLineAndStatementNumbers; |
363 | size_t lineAndStatementNumberOffset() const { return localsOffset + nLocals * sizeof(quint32); } |
364 | quint32_le nestedFunctionIndex; // for functions that only return a single closure, used in signal handlers |
365 | |
366 | quint32_le nRegisters; |
367 | Location location; |
368 | quint32_le nLabelInfos; |
369 | |
370 | quint16_le sizeOfLocalTemporalDeadZone; |
371 | quint16_le firstTemporalDeadZoneRegister; |
372 | quint16_le sizeOfRegisterTemporalDeadZone; |
373 | |
374 | size_t labelInfosOffset() const |
375 | { |
376 | return lineAndStatementNumberOffset() + nLineAndStatementNumbers * sizeof(CodeOffsetToLineAndStatement); |
377 | } |
378 | |
379 | // Keep all unaligned data at the end |
380 | quint8 flags; |
381 | quint8 padding1; |
382 | |
383 | // quint32 formalsIndex[nFormals] |
384 | // quint32 localsIndex[nLocals] |
385 | |
386 | const Parameter *formalsTable() const |
387 | { |
388 | return reinterpret_cast<const Parameter *>( |
389 | reinterpret_cast<const char *>(this) + formalsOffset); |
390 | } |
391 | const quint32_le *localsTable() const |
392 | { |
393 | return reinterpret_cast<const quint32_le *>( |
394 | reinterpret_cast<const char *>(this) + localsOffset); |
395 | } |
396 | const CodeOffsetToLineAndStatement *lineAndStatementNumberTable() const |
397 | { |
398 | return reinterpret_cast<const CodeOffsetToLineAndStatement *>( |
399 | reinterpret_cast<const char *>(this) + lineAndStatementNumberOffset()); |
400 | } |
401 | |
402 | // --- QQmlPropertyCacheCreator interface |
403 | const Parameter *formalsBegin() const { return formalsTable(); } |
404 | const Parameter *formalsEnd() const { return formalsTable() + nFormals; } |
405 | // --- |
406 | |
407 | const quint32_le *labelInfoTable() const { return reinterpret_cast<const quint32_le *>(reinterpret_cast<const char *>(this) + labelInfosOffset()); } |
408 | |
409 | const char *code() const { return reinterpret_cast<const char *>(this) + codeOffset; } |
410 | |
411 | static int calculateSize( |
412 | int nFormals, int nLocals, int nLinesAndStatements, int nInnerfunctions, |
413 | int labelInfoSize, int codeSize) |
414 | { |
415 | int trailingData = nFormals * sizeof(Parameter) |
416 | + (nLocals + nInnerfunctions + labelInfoSize) * sizeof (quint32) |
417 | + nLinesAndStatements * sizeof(CodeOffsetToLineAndStatement); |
418 | size_t size = align(a: align(a: sizeof(Function)) + size_t(trailingData)) + align(a: codeSize); |
419 | Q_ASSERT(size < INT_MAX); |
420 | return int(size); |
421 | } |
422 | |
423 | static size_t align(size_t a) { |
424 | return (a + 7) & ~size_t(7); |
425 | } |
426 | }; |
427 | 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" ); |
428 | |
429 | struct Method { |
430 | enum Type { |
431 | Regular, |
432 | Getter, |
433 | Setter |
434 | }; |
435 | |
436 | quint32_le name; |
437 | quint32_le type; |
438 | quint32_le function; |
439 | }; |
440 | 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" ); |
441 | |
442 | struct Class |
443 | { |
444 | quint32_le nameIndex; |
445 | quint32_le scopeIndex; |
446 | quint32_le constructorFunction; |
447 | quint32_le nStaticMethods; |
448 | quint32_le nMethods; |
449 | quint32_le methodTableOffset; |
450 | |
451 | const Method *methodTable() const { return reinterpret_cast<const Method *>(reinterpret_cast<const char *>(this) + methodTableOffset); } |
452 | |
453 | static int calculateSize(int nStaticMethods, int nMethods) { |
454 | int trailingData = (nStaticMethods + nMethods) * sizeof(Method); |
455 | size_t size = align(a: sizeof(Class) + trailingData); |
456 | Q_ASSERT(size < INT_MAX); |
457 | return int(size); |
458 | } |
459 | |
460 | static size_t align(size_t a) { |
461 | return (a + 7) & ~size_t(7); |
462 | } |
463 | }; |
464 | 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" ); |
465 | |
466 | struct TemplateObject |
467 | { |
468 | quint32_le size; |
469 | |
470 | static int calculateSize(int size) { |
471 | int trailingData = 2 * size * sizeof(quint32_le); |
472 | size_t s = align(a: sizeof(TemplateObject) + trailingData); |
473 | Q_ASSERT(s < INT_MAX); |
474 | return int(s); |
475 | } |
476 | |
477 | static size_t align(size_t a) { |
478 | return (a + 7) & ~size_t(7); |
479 | } |
480 | |
481 | const quint32_le *stringTable() const { |
482 | return reinterpret_cast<const quint32_le *>(reinterpret_cast<const char *>(this + 1)); |
483 | } |
484 | |
485 | uint stringIndexAt(uint i) const { |
486 | return stringTable()[i]; |
487 | } |
488 | uint rawStringIndexAt(uint i) const { |
489 | return stringTable()[size + i]; |
490 | } |
491 | }; |
492 | 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" ); |
493 | |
494 | struct ExportEntry |
495 | { |
496 | quint32_le exportName; |
497 | quint32_le moduleRequest; |
498 | quint32_le importName; |
499 | quint32_le localName; |
500 | Location location; |
501 | }; |
502 | 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" ); |
503 | |
504 | struct ImportEntry |
505 | { |
506 | quint32_le moduleRequest; |
507 | quint32_le importName; |
508 | quint32_le localName; |
509 | Location location; |
510 | }; |
511 | 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" ); |
512 | |
513 | // Qml data structures |
514 | |
515 | struct TranslationData |
516 | { |
517 | quint32_le stringIndex; |
518 | quint32_le ; |
519 | qint32_le number; |
520 | quint32_le contextIndex; |
521 | }; |
522 | 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" ); |
523 | |
524 | struct Binding |
525 | { |
526 | quint32_le propertyNameIndex; |
527 | |
528 | enum Type : unsigned int { |
529 | Type_Invalid, |
530 | Type_Boolean, |
531 | Type_Number, |
532 | Type_String, |
533 | Type_Null, |
534 | Type_Translation, |
535 | Type_TranslationById, |
536 | Type_Script, |
537 | Type_Object, |
538 | Type_AttachedProperty, |
539 | Type_GroupProperty |
540 | }; |
541 | |
542 | enum Flag : unsigned int { |
543 | IsSignalHandlerExpression = 0x1, |
544 | IsSignalHandlerObject = 0x2, |
545 | IsOnAssignment = 0x4, |
546 | InitializerForReadOnlyDeclaration = 0x8, |
547 | IsResolvedEnum = 0x10, |
548 | IsListItem = 0x20, |
549 | IsBindingToAlias = 0x40, |
550 | IsDeferredBinding = 0x80, |
551 | IsCustomParserBinding = 0x100, |
552 | IsFunctionExpression = 0x200, |
553 | IsPropertyObserver = 0x400 |
554 | }; |
555 | Q_DECLARE_FLAGS(Flags, Flag); |
556 | |
557 | using FlagsField = quint32_le_bitfield_member<0, 16>; |
558 | using TypeField = quint32_le_bitfield_member<16, 16>; |
559 | quint32_le_bitfield_union<FlagsField, TypeField> flagsAndType; |
560 | |
561 | void clearFlags() { flagsAndType.set<FlagsField>(0); } |
562 | void setFlag(Flag flag) { flagsAndType.set<FlagsField>(flagsAndType.get<FlagsField>() | flag); } |
563 | bool hasFlag(Flag flag) const { return Flags(flagsAndType.get<FlagsField>()) & flag; } |
564 | Flags flags() const { return Flags(flagsAndType.get<FlagsField>()); } |
565 | |
566 | void setType(Type type) { flagsAndType.set<TypeField>(type); } |
567 | Type type() const { return Type(flagsAndType.get<TypeField>()); } |
568 | |
569 | union { |
570 | bool b; |
571 | quint32_le constantValueIndex; |
572 | quint32_le compiledScriptIndex; // used when Type_Script |
573 | quint32_le objectIndex; |
574 | quint32_le translationDataIndex; // used when Type_Translation |
575 | quint32 nullMarker; |
576 | } value; |
577 | quint32_le stringIndex; // Set for Type_String and Type_Script (the latter because of script strings) |
578 | |
579 | Location location; |
580 | Location valueLocation; |
581 | |
582 | bool hasSignalHandlerBindingFlag() const |
583 | { |
584 | const Flags bindingFlags = flags(); |
585 | return bindingFlags & IsSignalHandlerExpression |
586 | || bindingFlags & IsSignalHandlerObject |
587 | || bindingFlags & IsPropertyObserver; |
588 | } |
589 | |
590 | bool isValueBinding() const |
591 | { |
592 | switch (type()) { |
593 | case Type_AttachedProperty: |
594 | case Type_GroupProperty: |
595 | return false; |
596 | default: |
597 | return !hasSignalHandlerBindingFlag(); |
598 | } |
599 | } |
600 | |
601 | bool isValueBindingNoAlias() const { return isValueBinding() && !hasFlag(flag: IsBindingToAlias); } |
602 | bool isValueBindingToAlias() const { return isValueBinding() && hasFlag(flag: IsBindingToAlias); } |
603 | |
604 | bool isSignalHandler() const |
605 | { |
606 | if (hasSignalHandlerBindingFlag()) { |
607 | Q_ASSERT(!isValueBinding()); |
608 | Q_ASSERT(!isAttachedProperty()); |
609 | Q_ASSERT(!isGroupProperty()); |
610 | return true; |
611 | } |
612 | return false; |
613 | } |
614 | |
615 | bool isAttachedProperty() const |
616 | { |
617 | if (type() == Type_AttachedProperty) { |
618 | Q_ASSERT(!isValueBinding()); |
619 | Q_ASSERT(!isSignalHandler()); |
620 | Q_ASSERT(!isGroupProperty()); |
621 | return true; |
622 | } |
623 | return false; |
624 | } |
625 | |
626 | bool isGroupProperty() const |
627 | { |
628 | if (type() == Type_GroupProperty) { |
629 | Q_ASSERT(!isValueBinding()); |
630 | Q_ASSERT(!isSignalHandler()); |
631 | Q_ASSERT(!isAttachedProperty()); |
632 | return true; |
633 | } |
634 | return false; |
635 | } |
636 | |
637 | bool isFunctionExpression() const { return hasFlag(flag: IsFunctionExpression); } |
638 | |
639 | //reverse of Lexer::singleEscape() |
640 | static QString escapedString(const QString &string) |
641 | { |
642 | QString tmp = QLatin1String("\"" ); |
643 | for (int i = 0; i < string.size(); ++i) { |
644 | const QChar &c = string.at(i); |
645 | switch (c.unicode()) { |
646 | case 0x08: |
647 | tmp += QLatin1String("\\b" ); |
648 | break; |
649 | case 0x09: |
650 | tmp += QLatin1String("\\t" ); |
651 | break; |
652 | case 0x0A: |
653 | tmp += QLatin1String("\\n" ); |
654 | break; |
655 | case 0x0B: |
656 | tmp += QLatin1String("\\v" ); |
657 | break; |
658 | case 0x0C: |
659 | tmp += QLatin1String("\\f" ); |
660 | break; |
661 | case 0x0D: |
662 | tmp += QLatin1String("\\r" ); |
663 | break; |
664 | case 0x22: |
665 | tmp += QLatin1String("\\\"" ); |
666 | break; |
667 | case 0x27: |
668 | tmp += QLatin1String("\\\'" ); |
669 | break; |
670 | case 0x5C: |
671 | tmp += QLatin1String("\\\\" ); |
672 | break; |
673 | default: |
674 | tmp += c; |
675 | break; |
676 | } |
677 | } |
678 | tmp += QLatin1Char('\"'); |
679 | return tmp; |
680 | } |
681 | |
682 | bool isTranslationBinding() const |
683 | { |
684 | const Binding::Type bindingType = type(); |
685 | return bindingType == Type_Translation || bindingType == Type_TranslationById; |
686 | } |
687 | bool evaluatesToString() const { return type() == Type_String || isTranslationBinding(); } |
688 | |
689 | bool valueAsBoolean() const |
690 | { |
691 | if (type() == Type_Boolean) |
692 | return value.b; |
693 | return false; |
694 | } |
695 | }; |
696 | |
697 | 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" ); |
698 | |
699 | struct InlineComponent |
700 | { |
701 | quint32_le objectIndex; |
702 | quint32_le nameIndex; |
703 | Location location; |
704 | }; |
705 | |
706 | 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" ); |
707 | |
708 | struct EnumValue |
709 | { |
710 | quint32_le nameIndex; |
711 | qint32_le value; |
712 | Location location; |
713 | }; |
714 | 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" ); |
715 | |
716 | struct Enum |
717 | { |
718 | quint32_le nameIndex; |
719 | quint32_le nEnumValues; |
720 | Location location; |
721 | |
722 | const EnumValue *enumValueAt(int idx) const { |
723 | return reinterpret_cast<const EnumValue*>(this + 1) + idx; |
724 | } |
725 | |
726 | static int calculateSize(int nEnumValues) { |
727 | return (sizeof(Enum) |
728 | + nEnumValues * sizeof(EnumValue) |
729 | + 7) & ~0x7; |
730 | } |
731 | |
732 | // --- QQmlPropertyCacheCreatorInterface |
733 | const EnumValue *enumValuesBegin() const { return enumValueAt(idx: 0); } |
734 | const EnumValue *enumValuesEnd() const { return enumValueAt(idx: nEnumValues); } |
735 | int enumValueCount() const { return nEnumValues; } |
736 | // --- |
737 | }; |
738 | 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" ); |
739 | |
740 | struct Signal |
741 | { |
742 | quint32_le nameIndex; |
743 | quint32_le nParameters; |
744 | Location location; |
745 | // Parameter parameters[1]; |
746 | |
747 | const Parameter *parameterAt(int idx) const { |
748 | return reinterpret_cast<const Parameter*>(this + 1) + idx; |
749 | } |
750 | |
751 | static int calculateSize(int nParameters) { |
752 | return (sizeof(Signal) |
753 | + nParameters * sizeof(Parameter) |
754 | + 7) & ~0x7; |
755 | } |
756 | |
757 | // --- QQmlPropertyCacheCceatorInterface |
758 | const Parameter *parametersBegin() const { return parameterAt(idx: 0); } |
759 | const Parameter *parametersEnd() const { return parameterAt(idx: nParameters); } |
760 | int parameterCount() const { return nParameters; } |
761 | // --- |
762 | }; |
763 | 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" ); |
764 | |
765 | struct Property |
766 | { |
767 | private: |
768 | using CommonTypeOrTypeNameIndexField = quint32_le_bitfield_member<0, 28>; |
769 | using IsRequiredField = quint32_le_bitfield_member<28, 1>; |
770 | using IsCommonTypeField = quint32_le_bitfield_member<29, 1>; |
771 | using IsListField = quint32_le_bitfield_member<30, 1>; |
772 | using IsReadOnlyField = quint32_le_bitfield_member<31, 1>; |
773 | |
774 | public: |
775 | quint32_le nameIndex; |
776 | quint32_le_bitfield_union< |
777 | CommonTypeOrTypeNameIndexField, |
778 | IsRequiredField, |
779 | IsCommonTypeField, |
780 | IsListField, |
781 | IsReadOnlyField> data; |
782 | Location location; |
783 | |
784 | void setCommonType(CommonType t) |
785 | { |
786 | data.set<CommonTypeOrTypeNameIndexField>(static_cast<quint32>(t)); |
787 | data.set<IsCommonTypeField>(true); |
788 | } |
789 | |
790 | CommonType commonType() const { |
791 | if (data.get<IsCommonTypeField>() != 0) |
792 | return CommonType(data.get<CommonTypeOrTypeNameIndexField>()); |
793 | return CommonType::Invalid; |
794 | } |
795 | |
796 | void setTypeNameIndex(int nameIndex) |
797 | { |
798 | data.set<CommonTypeOrTypeNameIndexField>(nameIndex); |
799 | data.set<IsCommonTypeField>(false); |
800 | } |
801 | |
802 | int typeNameIndex() const |
803 | { |
804 | return data.get<IsCommonTypeField>() ? -1 : data.get<CommonTypeOrTypeNameIndexField>(); |
805 | } |
806 | |
807 | bool isCommonType() const { return data.get<IsCommonTypeField>(); } |
808 | uint commonTypeOrTypeNameIndex() const { return data.get<CommonTypeOrTypeNameIndexField>(); } |
809 | |
810 | bool isList() const { return data.get<IsListField>(); } |
811 | void setIsList(bool isList) { data.set<IsListField>(isList); } |
812 | |
813 | bool isRequired() const { return data.get<IsRequiredField>(); } |
814 | void setIsRequired(bool isRequired) { data.set<IsRequiredField>(isRequired); } |
815 | |
816 | bool isReadOnly() const { return data.get<IsReadOnlyField>(); } |
817 | void setIsReadOnly(bool isReadOnly) { data.set<IsReadOnlyField>(isReadOnly); } |
818 | }; |
819 | 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" ); |
820 | |
821 | struct { |
822 | quint32_le ; |
823 | }; |
824 | |
825 | 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" ); |
826 | |
827 | struct Alias { |
828 | private: |
829 | using NameIndexField = quint32_le_bitfield_member<0, 29>; |
830 | using FlagsField = quint32_le_bitfield_member<29, 3>; |
831 | |
832 | // object id index (in QQmlContextData::idValues) |
833 | using TargetObjectIdField = quint32_le_bitfield_member<0, 31>; |
834 | using AliasToLocalAliasField = quint32_le_bitfield_member<31, 1>; |
835 | using IdIndexField = quint32_le_bitfield_member<0, 32>; |
836 | |
837 | public: |
838 | |
839 | enum Flag : unsigned int { |
840 | IsReadOnly = 0x1, |
841 | Resolved = 0x2, |
842 | AliasPointsToPointerObject = 0x4 |
843 | }; |
844 | Q_DECLARE_FLAGS(Flags, Flag) |
845 | |
846 | quint32_le_bitfield_union<NameIndexField, FlagsField> nameIndexAndFlags; |
847 | quint32_le_bitfield_union<IdIndexField, TargetObjectIdField, AliasToLocalAliasField> |
848 | idIndexAndTargetObjectIdAndAliasToLocalAlias; |
849 | |
850 | union { |
851 | quint32_le propertyNameIndex; // string index |
852 | qint32_le encodedMetaPropertyIndex; |
853 | quint32_le localAliasIndex; // index in list of aliases local to the object (if targetObjectId == objectId) |
854 | }; |
855 | Location location; |
856 | Location referenceLocation; |
857 | |
858 | bool hasFlag(Flag flag) const |
859 | { |
860 | return nameIndexAndFlags.get<FlagsField>() & flag; |
861 | } |
862 | |
863 | void setFlag(Flag flag) |
864 | { |
865 | nameIndexAndFlags.set<FlagsField>(nameIndexAndFlags.get<FlagsField>() | flag); |
866 | } |
867 | |
868 | void clearFlags() |
869 | { |
870 | nameIndexAndFlags.set<FlagsField>(0); |
871 | } |
872 | |
873 | quint32 nameIndex() const |
874 | { |
875 | return nameIndexAndFlags.get<NameIndexField>(); |
876 | } |
877 | |
878 | void setNameIndex(quint32 nameIndex) |
879 | { |
880 | nameIndexAndFlags.set<NameIndexField>(nameIndex); |
881 | } |
882 | |
883 | bool isObjectAlias() const |
884 | { |
885 | Q_ASSERT(hasFlag(Resolved)); |
886 | return encodedMetaPropertyIndex == -1; |
887 | } |
888 | |
889 | quint32 idIndex() const |
890 | { |
891 | return idIndexAndTargetObjectIdAndAliasToLocalAlias.get<IdIndexField>(); |
892 | } |
893 | |
894 | void setIdIndex(quint32 idIndex) |
895 | { |
896 | idIndexAndTargetObjectIdAndAliasToLocalAlias.set<IdIndexField>(idIndex); |
897 | } |
898 | |
899 | |
900 | bool isAliasToLocalAlias() const |
901 | { |
902 | return idIndexAndTargetObjectIdAndAliasToLocalAlias.get<AliasToLocalAliasField>(); |
903 | } |
904 | |
905 | void setIsAliasToLocalAlias(bool isAliasToLocalAlias) |
906 | { |
907 | idIndexAndTargetObjectIdAndAliasToLocalAlias.set<AliasToLocalAliasField>(isAliasToLocalAlias); |
908 | } |
909 | |
910 | quint32 targetObjectId() const |
911 | { |
912 | return idIndexAndTargetObjectIdAndAliasToLocalAlias.get<TargetObjectIdField>(); |
913 | } |
914 | |
915 | void setTargetObjectId(quint32 targetObjectId) |
916 | { |
917 | idIndexAndTargetObjectIdAndAliasToLocalAlias.set<TargetObjectIdField>(targetObjectId); |
918 | } |
919 | }; |
920 | 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" ); |
921 | |
922 | struct Object |
923 | { |
924 | private: |
925 | using FlagsField = quint32_le_bitfield_member<0, 15>; |
926 | using DefaultPropertyIsAliasField = quint32_le_bitfield_member<15, 1>; |
927 | using IdField = quint32_le_bitfield_member<16, 16, qint32>; |
928 | public: |
929 | enum Flag : unsigned int { |
930 | NoFlag = 0x0, |
931 | IsComponent = 0x1, // object was identified to be an explicit or implicit component boundary |
932 | HasDeferredBindings = 0x2, // any of the bindings are deferred |
933 | HasCustomParserBindings = 0x4, |
934 | IsInlineComponentRoot = 0x8, |
935 | IsPartOfInlineComponent = 0x10 |
936 | }; |
937 | Q_DECLARE_FLAGS(Flags, Flag); |
938 | |
939 | // Depending on the use, this may be the type name to instantiate before instantiating this |
940 | // object. For grouped properties the type name will be empty and for attached properties |
941 | // it will be the name of the attached type. |
942 | quint32_le inheritedTypeNameIndex; |
943 | quint32_le idNameIndex; |
944 | quint32_le_bitfield_union<FlagsField, DefaultPropertyIsAliasField, IdField> |
945 | flagsAndDefaultPropertyIsAliasAndId; |
946 | qint32_le indexOfDefaultPropertyOrAlias; // -1 means no default property declared in this object |
947 | quint16_le nFunctions; |
948 | quint16_le nProperties; |
949 | quint32_le offsetToFunctions; |
950 | quint32_le offsetToProperties; |
951 | quint32_le offsetToAliases; |
952 | quint16_le nAliases; |
953 | quint16_le nEnums; |
954 | quint32_le offsetToEnums; // which in turn will be a table with offsets to variable-sized Enum objects |
955 | quint32_le offsetToSignals; // which in turn will be a table with offsets to variable-sized Signal objects |
956 | quint16_le nSignals; |
957 | quint16_le nBindings; |
958 | quint32_le offsetToBindings; |
959 | quint32_le nNamedObjectsInComponent; |
960 | quint32_le offsetToNamedObjectsInComponent; |
961 | Location location; |
962 | Location locationOfIdProperty; |
963 | quint32_le offsetToInlineComponents; |
964 | quint16_le nInlineComponents; |
965 | quint32_le ; |
966 | quint16_le ; |
967 | // Function[] |
968 | // Property[] |
969 | // Signal[] |
970 | // Binding[] |
971 | // InlineComponent[] |
972 | // RequiredPropertyExtraData[] |
973 | |
974 | Flags flags() const |
975 | { |
976 | return Flags(flagsAndDefaultPropertyIsAliasAndId.get<FlagsField>()); |
977 | } |
978 | |
979 | bool hasFlag(Flag flag) const |
980 | { |
981 | return flagsAndDefaultPropertyIsAliasAndId.get<FlagsField>() & flag; |
982 | } |
983 | |
984 | void setFlag(Flag flag) |
985 | { |
986 | flagsAndDefaultPropertyIsAliasAndId.set<FlagsField>( |
987 | flagsAndDefaultPropertyIsAliasAndId.get<FlagsField>() | flag); |
988 | } |
989 | |
990 | void setFlags(Flags flags) |
991 | { |
992 | flagsAndDefaultPropertyIsAliasAndId.set<FlagsField>(flags); |
993 | } |
994 | |
995 | bool hasAliasAsDefaultProperty() const |
996 | { |
997 | return flagsAndDefaultPropertyIsAliasAndId.get<DefaultPropertyIsAliasField>(); |
998 | } |
999 | |
1000 | void setHasAliasAsDefaultProperty(bool defaultAlias) |
1001 | { |
1002 | flagsAndDefaultPropertyIsAliasAndId.set<DefaultPropertyIsAliasField>(defaultAlias); |
1003 | } |
1004 | |
1005 | qint32 objectId() const |
1006 | { |
1007 | return flagsAndDefaultPropertyIsAliasAndId.get<IdField>(); |
1008 | } |
1009 | |
1010 | void setObjectId(qint32 id) |
1011 | { |
1012 | flagsAndDefaultPropertyIsAliasAndId.set<IdField>(id); |
1013 | } |
1014 | |
1015 | |
1016 | static int calculateSizeExcludingSignalsAndEnums(int nFunctions, int nProperties, int nAliases, int nEnums, int nSignals, int nBindings, int nNamedObjectsInComponent, int nInlineComponents, int ) |
1017 | { |
1018 | return ( sizeof(Object) |
1019 | + nFunctions * sizeof(quint32) |
1020 | + nProperties * sizeof(Property) |
1021 | + nAliases * sizeof(Alias) |
1022 | + nEnums * sizeof(quint32) |
1023 | + nSignals * sizeof(quint32) |
1024 | + nBindings * sizeof(Binding) |
1025 | + nNamedObjectsInComponent * sizeof(int) |
1026 | + nInlineComponents * sizeof(InlineComponent) |
1027 | + nRequiredPropertyExtraData * sizeof(RequiredPropertyExtraData) |
1028 | + 0x7 |
1029 | ) & ~0x7; |
1030 | } |
1031 | |
1032 | const quint32_le *functionOffsetTable() const |
1033 | { |
1034 | return reinterpret_cast<const quint32_le*>(reinterpret_cast<const char *>(this) + offsetToFunctions); |
1035 | } |
1036 | |
1037 | const Property *propertyTable() const |
1038 | { |
1039 | return reinterpret_cast<const Property*>(reinterpret_cast<const char *>(this) + offsetToProperties); |
1040 | } |
1041 | |
1042 | const Alias *aliasTable() const |
1043 | { |
1044 | return reinterpret_cast<const Alias*>(reinterpret_cast<const char *>(this) + offsetToAliases); |
1045 | } |
1046 | |
1047 | const Binding *bindingTable() const |
1048 | { |
1049 | return reinterpret_cast<const Binding*>(reinterpret_cast<const char *>(this) + offsetToBindings); |
1050 | } |
1051 | |
1052 | const Enum *enumAt(int idx) const |
1053 | { |
1054 | const quint32_le *offsetTable = reinterpret_cast<const quint32_le*>((reinterpret_cast<const char *>(this)) + offsetToEnums); |
1055 | const quint32_le offset = offsetTable[idx]; |
1056 | return reinterpret_cast<const Enum*>(reinterpret_cast<const char*>(this) + offset); |
1057 | } |
1058 | |
1059 | const Signal *signalAt(int idx) const |
1060 | { |
1061 | const quint32_le *offsetTable = reinterpret_cast<const quint32_le*>((reinterpret_cast<const char *>(this)) + offsetToSignals); |
1062 | const quint32_le offset = offsetTable[idx]; |
1063 | return reinterpret_cast<const Signal*>(reinterpret_cast<const char*>(this) + offset); |
1064 | } |
1065 | |
1066 | const InlineComponent *inlineComponentAt(int idx) const |
1067 | { |
1068 | return inlineComponentTable() + idx; |
1069 | } |
1070 | |
1071 | const quint32_le *namedObjectsInComponentTable() const |
1072 | { |
1073 | return reinterpret_cast<const quint32_le*>(reinterpret_cast<const char *>(this) + offsetToNamedObjectsInComponent); |
1074 | } |
1075 | |
1076 | const InlineComponent *inlineComponentTable() const |
1077 | { |
1078 | return reinterpret_cast<const InlineComponent*>(reinterpret_cast<const char *>(this) + offsetToInlineComponents); |
1079 | } |
1080 | |
1081 | const RequiredPropertyExtraData *(int idx) const |
1082 | { |
1083 | return requiredPropertyExtraDataTable() + idx; |
1084 | } |
1085 | |
1086 | const RequiredPropertyExtraData *() const |
1087 | { |
1088 | return reinterpret_cast<const RequiredPropertyExtraData*>(reinterpret_cast<const char *>(this) + offsetToRequiredPropertyExtraData); |
1089 | } |
1090 | |
1091 | // --- QQmlPropertyCacheCreator interface |
1092 | int propertyCount() const { return nProperties; } |
1093 | int aliasCount() const { return nAliases; } |
1094 | int enumCount() const { return nEnums; } |
1095 | int signalCount() const { return nSignals; } |
1096 | int functionCount() const { return nFunctions; } |
1097 | |
1098 | const Binding *bindingsBegin() const { return bindingTable(); } |
1099 | const Binding *bindingsEnd() const { return bindingTable() + nBindings; } |
1100 | int bindingCount() const { return nBindings; } |
1101 | |
1102 | const Property *propertiesBegin() const { return propertyTable(); } |
1103 | const Property *propertiesEnd() const { return propertyTable() + nProperties; } |
1104 | |
1105 | const Alias *aliasesBegin() const { return aliasTable(); } |
1106 | const Alias *aliasesEnd() const { return aliasTable() + nAliases; } |
1107 | |
1108 | typedef TableIterator<Enum, Object, &Object::enumAt> EnumIterator; |
1109 | EnumIterator enumsBegin() const { return EnumIterator(this, 0); } |
1110 | EnumIterator enumsEnd() const { return EnumIterator(this, nEnums); } |
1111 | |
1112 | typedef TableIterator<Signal, Object, &Object::signalAt> SignalIterator; |
1113 | SignalIterator signalsBegin() const { return SignalIterator(this, 0); } |
1114 | SignalIterator signalsEnd() const { return SignalIterator(this, nSignals); } |
1115 | |
1116 | typedef TableIterator<InlineComponent, Object, &Object::inlineComponentAt> InlineComponentIterator; |
1117 | InlineComponentIterator inlineComponentsBegin() const {return InlineComponentIterator(this, 0);} |
1118 | InlineComponentIterator inlineComponentsEnd() const {return InlineComponentIterator(this, nInlineComponents);} |
1119 | |
1120 | typedef TableIterator<RequiredPropertyExtraData, Object, &Object::requiredPropertyExtraDataAt> ; |
1121 | RequiredPropertyExtraDataIterator () const {return RequiredPropertyExtraDataIterator(this, 0); } |
1122 | RequiredPropertyExtraDataIterator () const {return RequiredPropertyExtraDataIterator(this, nRequiredPropertyExtraData); } |
1123 | |
1124 | int namedObjectsInComponentCount() const { return nNamedObjectsInComponent; } |
1125 | // --- |
1126 | }; |
1127 | 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" ); |
1128 | |
1129 | struct Import |
1130 | { |
1131 | enum ImportType : unsigned int { |
1132 | ImportLibrary = 0x1, |
1133 | ImportFile = 0x2, |
1134 | ImportScript = 0x3, |
1135 | ImportInlineComponent = 0x4 |
1136 | }; |
1137 | quint32_le type; |
1138 | |
1139 | quint32_le uriIndex; |
1140 | quint32_le qualifierIndex; |
1141 | |
1142 | Location location; |
1143 | QTypeRevision version; |
1144 | quint16_le reserved; |
1145 | |
1146 | Import() |
1147 | { |
1148 | type = 0; uriIndex = 0; qualifierIndex = 0; version = QTypeRevision::zero(); reserved = 0; |
1149 | } |
1150 | }; |
1151 | static_assert(sizeof(Import) == 20, "Import structure needs to have the expected size to be binary compatible on disk when generated by host compiler and loaded by target" ); |
1152 | |
1153 | struct QmlUnit |
1154 | { |
1155 | quint32_le nImports; |
1156 | quint32_le offsetToImports; |
1157 | quint32_le nObjects; |
1158 | quint32_le offsetToObjects; |
1159 | |
1160 | const Import *importAt(int idx) const { |
1161 | return reinterpret_cast<const Import*>((reinterpret_cast<const char *>(this)) + offsetToImports + idx * sizeof(Import)); |
1162 | } |
1163 | |
1164 | const Object *objectAt(int idx) const { |
1165 | const quint32_le *offsetTable = reinterpret_cast<const quint32_le*>((reinterpret_cast<const char *>(this)) + offsetToObjects); |
1166 | const quint32_le offset = offsetTable[idx]; |
1167 | return reinterpret_cast<const Object*>(reinterpret_cast<const char*>(this) + offset); |
1168 | } |
1169 | }; |
1170 | 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" ); |
1171 | |
1172 | enum { QmlCompileHashSpace = 48 }; |
1173 | static const char magic_str[] = "qv4cdata" ; |
1174 | |
1175 | struct Unit |
1176 | { |
1177 | // DO NOT CHANGE THESE FIELDS EVER |
1178 | char magic[8]; |
1179 | quint32_le version; |
1180 | quint32_le qtVersion; |
1181 | qint64_le sourceTimeStamp; |
1182 | quint32_le unitSize; // Size of the Unit and any depending data. |
1183 | // END DO NOT CHANGE THESE FIELDS EVER |
1184 | |
1185 | char libraryVersionHash[QmlCompileHashSpace]; |
1186 | |
1187 | char md5Checksum[16]; // checksum of all bytes following this field. |
1188 | char dependencyMD5Checksum[16]; |
1189 | |
1190 | enum : unsigned int { |
1191 | IsJavascript = 0x1, |
1192 | StaticData = 0x2, // Unit data persistent in memory? |
1193 | IsSingleton = 0x4, |
1194 | IsSharedLibrary = 0x8, // .pragma shared? |
1195 | IsESModule = 0x10, |
1196 | PendingTypeCompilation = 0x20, // the QML data structures present are incomplete and require type compilation |
1197 | IsStrict = 0x40, |
1198 | ListPropertyAssignReplaceIfDefault = 0x80, |
1199 | ListPropertyAssignReplaceIfNotDefault = 0x100, |
1200 | ListPropertyAssignReplace |
1201 | = ListPropertyAssignReplaceIfDefault | ListPropertyAssignReplaceIfNotDefault, |
1202 | ComponentsBound = 0x200, |
1203 | FunctionSignaturesEnforced = 0x400, |
1204 | NativeMethodsAcceptThisObject = 0x800, |
1205 | ValueTypesCopied = 0x1000, |
1206 | ValueTypesAddressable = 0x2000, |
1207 | }; |
1208 | quint32_le flags; |
1209 | quint32_le stringTableSize; |
1210 | quint32_le offsetToStringTable; |
1211 | quint32_le functionTableSize; |
1212 | quint32_le offsetToFunctionTable; |
1213 | quint32_le classTableSize; |
1214 | quint32_le offsetToClassTable; |
1215 | quint32_le templateObjectTableSize; |
1216 | quint32_le offsetToTemplateObjectTable; |
1217 | quint32_le blockTableSize; |
1218 | quint32_le offsetToBlockTable; |
1219 | quint32_le lookupTableSize; |
1220 | quint32_le offsetToLookupTable; |
1221 | quint32_le regexpTableSize; |
1222 | quint32_le offsetToRegexpTable; |
1223 | quint32_le constantTableSize; |
1224 | quint32_le offsetToConstantTable; |
1225 | quint32_le jsClassTableSize; |
1226 | quint32_le offsetToJSClassTable; |
1227 | quint32_le translationTableSize; |
1228 | quint32_le offsetToTranslationTable; |
1229 | quint32_le localExportEntryTableSize; |
1230 | quint32_le offsetToLocalExportEntryTable; |
1231 | quint32_le indirectExportEntryTableSize; |
1232 | quint32_le offsetToIndirectExportEntryTable; |
1233 | quint32_le starExportEntryTableSize; |
1234 | quint32_le offsetToStarExportEntryTable; |
1235 | quint32_le importEntryTableSize; |
1236 | quint32_le offsetToImportEntryTable; |
1237 | quint32_le moduleRequestTableSize; |
1238 | quint32_le offsetToModuleRequestTable; |
1239 | qint32_le indexOfRootFunction; |
1240 | quint32_le sourceFileIndex; |
1241 | quint32_le finalUrlIndex; |
1242 | |
1243 | quint32_le offsetToQmlUnit; |
1244 | |
1245 | /* QML specific fields */ |
1246 | |
1247 | const QmlUnit *qmlUnit() const { |
1248 | return reinterpret_cast<const QmlUnit *>(reinterpret_cast<const char *>(this) + offsetToQmlUnit); |
1249 | } |
1250 | |
1251 | QmlUnit *qmlUnit() { |
1252 | return reinterpret_cast<QmlUnit *>(reinterpret_cast<char *>(this) + offsetToQmlUnit); |
1253 | } |
1254 | |
1255 | bool isSingleton() const { |
1256 | return flags & Unit::IsSingleton; |
1257 | } |
1258 | /* end QML specific fields*/ |
1259 | |
1260 | QString stringAtInternal(uint idx) const { |
1261 | Q_ASSERT(idx < stringTableSize); |
1262 | const quint32_le *offsetTable = reinterpret_cast<const quint32_le*>((reinterpret_cast<const char *>(this)) + offsetToStringTable); |
1263 | const quint32_le offset = offsetTable[idx]; |
1264 | const String *str = reinterpret_cast<const String*>(reinterpret_cast<const char *>(this) + offset); |
1265 | Q_ASSERT(str->size >= 0); |
1266 | if (str->size == 0) |
1267 | return QString(); |
1268 | #if Q_BYTE_ORDER == Q_LITTLE_ENDIAN |
1269 | const QChar *characters = reinterpret_cast<const QChar *>(str + 1); |
1270 | if (flags & StaticData) |
1271 | return QString::fromRawData(characters, size: str->size); |
1272 | return QString(characters, str->size); |
1273 | #else |
1274 | const quint16_le *characters = reinterpret_cast<const quint16_le *>(str + 1); |
1275 | QString qstr(str->size, Qt::Uninitialized); |
1276 | QChar *ch = qstr.data(); |
1277 | for (int i = 0; i < str->size; ++i) |
1278 | ch[i] = QChar(characters[i]); |
1279 | return qstr; |
1280 | #endif |
1281 | } |
1282 | |
1283 | const quint32_le *functionOffsetTable() const { return reinterpret_cast<const quint32_le*>((reinterpret_cast<const char *>(this)) + offsetToFunctionTable); } |
1284 | const quint32_le *classOffsetTable() const { return reinterpret_cast<const quint32_le*>((reinterpret_cast<const char *>(this)) + offsetToClassTable); } |
1285 | const quint32_le *templateObjectOffsetTable() const { return reinterpret_cast<const quint32_le*>((reinterpret_cast<const char *>(this)) + offsetToTemplateObjectTable); } |
1286 | const quint32_le *blockOffsetTable() const { return reinterpret_cast<const quint32_le*>((reinterpret_cast<const char *>(this)) + offsetToBlockTable); } |
1287 | |
1288 | const Function *functionAt(int idx) const { |
1289 | const quint32_le *offsetTable = functionOffsetTable(); |
1290 | const quint32_le offset = offsetTable[idx]; |
1291 | return reinterpret_cast<const Function*>(reinterpret_cast<const char *>(this) + offset); |
1292 | } |
1293 | |
1294 | const Class *classAt(int idx) const { |
1295 | const quint32_le *offsetTable = classOffsetTable(); |
1296 | const quint32_le offset = offsetTable[idx]; |
1297 | return reinterpret_cast<const Class *>(reinterpret_cast<const char *>(this) + offset); |
1298 | } |
1299 | |
1300 | const TemplateObject *templateObjectAt(int idx) const { |
1301 | const quint32_le *offsetTable = templateObjectOffsetTable(); |
1302 | const quint32_le offset = offsetTable[idx]; |
1303 | return reinterpret_cast<const TemplateObject *>(reinterpret_cast<const char *>(this) + offset); |
1304 | } |
1305 | |
1306 | const Block *blockAt(int idx) const { |
1307 | const quint32_le *offsetTable = blockOffsetTable(); |
1308 | const quint32_le offset = offsetTable[idx]; |
1309 | return reinterpret_cast<const Block *>(reinterpret_cast<const char *>(this) + offset); |
1310 | } |
1311 | |
1312 | const Lookup *lookupTable() const { return reinterpret_cast<const Lookup*>(reinterpret_cast<const char *>(this) + offsetToLookupTable); } |
1313 | const RegExp *regexpAt(int index) const { |
1314 | return reinterpret_cast<const RegExp*>(reinterpret_cast<const char *>(this) + offsetToRegexpTable + index * sizeof(RegExp)); |
1315 | } |
1316 | const quint64_le *constants() const { |
1317 | return reinterpret_cast<const quint64_le*>(reinterpret_cast<const char *>(this) + offsetToConstantTable); |
1318 | } |
1319 | |
1320 | const JSClassMember *jsClassAt(int idx, int *nMembers) const { |
1321 | const quint32_le *offsetTable = reinterpret_cast<const quint32_le *>(reinterpret_cast<const char *>(this) + offsetToJSClassTable); |
1322 | const quint32_le offset = offsetTable[idx]; |
1323 | const char *ptr = reinterpret_cast<const char *>(this) + offset; |
1324 | const JSClass *klass = reinterpret_cast<const JSClass *>(ptr); |
1325 | *nMembers = klass->nMembers; |
1326 | return reinterpret_cast<const JSClassMember*>(ptr + sizeof(JSClass)); |
1327 | } |
1328 | |
1329 | const TranslationData *translations() const { |
1330 | return reinterpret_cast<const TranslationData *>(reinterpret_cast<const char *>(this) + offsetToTranslationTable); |
1331 | } |
1332 | |
1333 | const ImportEntry *importEntryTable() const { return reinterpret_cast<const ImportEntry *>(reinterpret_cast<const char *>(this) + offsetToImportEntryTable); } |
1334 | const ExportEntry *localExportEntryTable() const { return reinterpret_cast<const ExportEntry *>(reinterpret_cast<const char *>(this) + offsetToLocalExportEntryTable); } |
1335 | const ExportEntry *indirectExportEntryTable() const { return reinterpret_cast<const ExportEntry *>(reinterpret_cast<const char *>(this) + offsetToIndirectExportEntryTable); } |
1336 | const ExportEntry *starExportEntryTable() const { return reinterpret_cast<const ExportEntry *>(reinterpret_cast<const char *>(this) + offsetToStarExportEntryTable); } |
1337 | |
1338 | const quint32_le *moduleRequestTable() const { return reinterpret_cast<const quint32_le*>((reinterpret_cast<const char *>(this)) + offsetToModuleRequestTable); } |
1339 | }; |
1340 | |
1341 | 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" ); |
1342 | |
1343 | struct TypeReference |
1344 | { |
1345 | TypeReference(const Location &loc) |
1346 | : location(loc) |
1347 | , needsCreation(false) |
1348 | , errorWhenNotFound(false) |
1349 | {} |
1350 | Location location; // first use |
1351 | bool needsCreation : 1; // whether the type needs to be creatable or not |
1352 | bool errorWhenNotFound: 1; |
1353 | }; |
1354 | |
1355 | // Map from name index to location of first use. |
1356 | struct TypeReferenceMap : QHash<int, TypeReference> |
1357 | { |
1358 | TypeReference &add(int nameIndex, const Location &loc) { |
1359 | Iterator it = find(key: nameIndex); |
1360 | if (it != end()) |
1361 | return *it; |
1362 | return *insert(key: nameIndex, value: loc); |
1363 | } |
1364 | |
1365 | template <typename CompiledObject> |
1366 | void collectFromObject(const CompiledObject *obj) |
1367 | { |
1368 | if (obj->inheritedTypeNameIndex != 0) { |
1369 | TypeReference &r = this->add(nameIndex: obj->inheritedTypeNameIndex, loc: obj->location); |
1370 | r.needsCreation = true; |
1371 | r.errorWhenNotFound = true; |
1372 | } |
1373 | |
1374 | auto prop = obj->propertiesBegin(); |
1375 | auto const propEnd = obj->propertiesEnd(); |
1376 | for ( ; prop != propEnd; ++prop) { |
1377 | if (!prop->isCommonType()) { |
1378 | TypeReference &r = this->add(nameIndex: prop->commonTypeOrTypeNameIndex(), loc: prop->location); |
1379 | r.errorWhenNotFound = true; |
1380 | } |
1381 | } |
1382 | |
1383 | auto binding = obj->bindingsBegin(); |
1384 | auto const bindingEnd = obj->bindingsEnd(); |
1385 | for ( ; binding != bindingEnd; ++binding) { |
1386 | if (binding->type() == QV4::CompiledData::Binding::Type_AttachedProperty) |
1387 | this->add(nameIndex: binding->propertyNameIndex, loc: binding->location); |
1388 | } |
1389 | |
1390 | auto ic = obj->inlineComponentsBegin(); |
1391 | auto const icEnd = obj->inlineComponentsEnd(); |
1392 | for (; ic != icEnd; ++ic) { |
1393 | this->add(nameIndex: ic->nameIndex, loc: ic->location); |
1394 | } |
1395 | } |
1396 | |
1397 | template <typename Iterator> |
1398 | void collectFromObjects(Iterator it, Iterator end) |
1399 | { |
1400 | for (; it != end; ++it) |
1401 | collectFromObject(*it); |
1402 | } |
1403 | }; |
1404 | |
1405 | using DependentTypesHasher = std::function<QByteArray()>; |
1406 | |
1407 | // This is how this hooks into the existing structures: |
1408 | |
1409 | struct CompilationUnitBase |
1410 | { |
1411 | Q_DISABLE_COPY(CompilationUnitBase) |
1412 | |
1413 | CompilationUnitBase() = default; |
1414 | ~CompilationUnitBase() = default; |
1415 | |
1416 | CompilationUnitBase(CompilationUnitBase &&other) noexcept { *this = std::move(other); } |
1417 | |
1418 | CompilationUnitBase &operator=(CompilationUnitBase &&other) noexcept |
1419 | { |
1420 | if (this != &other) { |
1421 | runtimeStrings = other.runtimeStrings; |
1422 | other.runtimeStrings = nullptr; |
1423 | constants = other.constants; |
1424 | other.constants = nullptr; |
1425 | runtimeRegularExpressions = other.runtimeRegularExpressions; |
1426 | other.runtimeRegularExpressions = nullptr; |
1427 | runtimeClasses = other.runtimeClasses; |
1428 | other.runtimeClasses = nullptr; |
1429 | imports = other.imports; |
1430 | other.imports = nullptr; |
1431 | } |
1432 | return *this; |
1433 | } |
1434 | |
1435 | // pointers either to data->constants() or little-endian memory copy. |
1436 | Heap::String **runtimeStrings = nullptr; // Array |
1437 | const StaticValue* constants = nullptr; |
1438 | QV4::StaticValue *runtimeRegularExpressions = nullptr; |
1439 | Heap::InternalClass **runtimeClasses = nullptr; |
1440 | const StaticValue** imports = nullptr; |
1441 | }; |
1442 | |
1443 | Q_STATIC_ASSERT(std::is_standard_layout<CompilationUnitBase>::value); |
1444 | Q_STATIC_ASSERT(offsetof(CompilationUnitBase, runtimeStrings) == 0); |
1445 | Q_STATIC_ASSERT(offsetof(CompilationUnitBase, constants) == sizeof(QV4::Heap::String **)); |
1446 | Q_STATIC_ASSERT(offsetof(CompilationUnitBase, runtimeRegularExpressions) == offsetof(CompilationUnitBase, constants) + sizeof(const StaticValue *)); |
1447 | Q_STATIC_ASSERT(offsetof(CompilationUnitBase, runtimeClasses) == offsetof(CompilationUnitBase, runtimeRegularExpressions) + sizeof(const StaticValue *)); |
1448 | Q_STATIC_ASSERT(offsetof(CompilationUnitBase, imports) == offsetof(CompilationUnitBase, runtimeClasses) + sizeof(const StaticValue *)); |
1449 | |
1450 | struct CompilationUnit : public CompilationUnitBase |
1451 | { |
1452 | Q_DISABLE_COPY(CompilationUnit) |
1453 | |
1454 | const Unit *data = nullptr; |
1455 | const QmlUnit *qmlData = nullptr; |
1456 | QStringList dynamicStrings; |
1457 | const QQmlPrivate::AOTCompiledFunction *aotCompiledFunctions = nullptr; |
1458 | public: |
1459 | using CompiledObject = CompiledData::Object; |
1460 | |
1461 | CompilationUnit(const Unit *unitData = nullptr, const QString &fileName = QString(), |
1462 | const QString &finalUrlString = QString()) |
1463 | { |
1464 | setUnitData(unitData, qmlUnit: nullptr, fileName, finalUrlString); |
1465 | } |
1466 | |
1467 | explicit CompilationUnit(const Unit *unitData, const QQmlPrivate::AOTCompiledFunction *aotCompiledFunctions, |
1468 | const QString &fileName = QString(), const QString &finalUrlString = QString()) |
1469 | : CompilationUnit(unitData, fileName, finalUrlString) |
1470 | { |
1471 | this->aotCompiledFunctions = aotCompiledFunctions; |
1472 | } |
1473 | |
1474 | ~CompilationUnit() |
1475 | { |
1476 | if (data) { |
1477 | if (data->qmlUnit() != qmlData) |
1478 | free(ptr: const_cast<QmlUnit *>(qmlData)); |
1479 | qmlData = nullptr; |
1480 | |
1481 | if (!(data->flags & QV4::CompiledData::Unit::StaticData)) |
1482 | free(ptr: const_cast<Unit *>(data)); |
1483 | } |
1484 | data = nullptr; |
1485 | #if Q_BYTE_ORDER == Q_BIG_ENDIAN |
1486 | delete [] constants; |
1487 | constants = nullptr; |
1488 | #endif |
1489 | |
1490 | delete [] imports; |
1491 | imports = nullptr; |
1492 | } |
1493 | |
1494 | CompilationUnit(CompilationUnit &&other) noexcept |
1495 | { |
1496 | *this = std::move(other); |
1497 | } |
1498 | |
1499 | CompilationUnit &operator=(CompilationUnit &&other) noexcept |
1500 | { |
1501 | if (this != &other) { |
1502 | data = other.data; |
1503 | other.data = nullptr; |
1504 | qmlData = other.qmlData; |
1505 | other.qmlData = nullptr; |
1506 | dynamicStrings = std::move(other.dynamicStrings); |
1507 | aotCompiledFunctions = other.aotCompiledFunctions; |
1508 | other.dynamicStrings.clear(); |
1509 | m_fileName = std::move(other.m_fileName); |
1510 | other.m_fileName.clear(); |
1511 | m_finalUrlString = std::move(other.m_finalUrlString); |
1512 | other.m_finalUrlString.clear(); |
1513 | m_module = other.m_module; |
1514 | other.m_module = nullptr; |
1515 | CompilationUnitBase::operator=(other: std::move(other)); |
1516 | } |
1517 | return *this; |
1518 | } |
1519 | |
1520 | const Unit *unitData() const { return data; } |
1521 | |
1522 | void setUnitData(const Unit *unitData, const QmlUnit *qmlUnit = nullptr, |
1523 | const QString &fileName = QString(), const QString &finalUrlString = QString()) |
1524 | { |
1525 | data = unitData; |
1526 | qmlData = nullptr; |
1527 | #if Q_BYTE_ORDER == Q_BIG_ENDIAN |
1528 | delete [] constants; |
1529 | #endif |
1530 | constants = nullptr; |
1531 | m_fileName.clear(); |
1532 | m_finalUrlString.clear(); |
1533 | if (!data) |
1534 | return; |
1535 | |
1536 | qmlData = qmlUnit ? qmlUnit : data->qmlUnit(); |
1537 | |
1538 | #if Q_BYTE_ORDER == Q_BIG_ENDIAN |
1539 | StaticValue *bigEndianConstants = new StaticValue[data->constantTableSize]; |
1540 | const quint64_le *littleEndianConstants = data->constants(); |
1541 | for (uint i = 0; i < data->constantTableSize; ++i) |
1542 | bigEndianConstants[i] = StaticValue::fromReturnedValue(littleEndianConstants[i]); |
1543 | constants = bigEndianConstants; |
1544 | #else |
1545 | constants = reinterpret_cast<const StaticValue*>(data->constants()); |
1546 | #endif |
1547 | |
1548 | m_fileName = !fileName.isEmpty() ? fileName : stringAt(index: data->sourceFileIndex); |
1549 | m_finalUrlString = !finalUrlString.isEmpty() ? finalUrlString : stringAt(index: data->finalUrlIndex); |
1550 | } |
1551 | |
1552 | QString stringAt(uint index) const |
1553 | { |
1554 | if (index < data->stringTableSize) |
1555 | return data->stringAtInternal(idx: index); |
1556 | |
1557 | const qsizetype dynamicIndex = index - data->stringTableSize; |
1558 | Q_ASSERT(dynamicIndex < dynamicStrings.size()); |
1559 | return dynamicStrings.at(i: dynamicIndex); |
1560 | } |
1561 | |
1562 | QString fileName() const { return m_fileName; } |
1563 | QString finalUrlString() const { return m_finalUrlString; } |
1564 | |
1565 | Heap::Module *module() const { return m_module; } |
1566 | void setModule(Heap::Module *module) { m_module = module; } |
1567 | |
1568 | QString bindingValueAsString(const CompiledData::Binding *binding) const |
1569 | { |
1570 | using namespace CompiledData; |
1571 | switch (binding->type()) { |
1572 | case Binding::Type_Script: |
1573 | case Binding::Type_String: |
1574 | return stringAt(index: binding->stringIndex); |
1575 | case Binding::Type_Null: |
1576 | return QStringLiteral("null" ); |
1577 | case Binding::Type_Boolean: |
1578 | return binding->value.b ? QStringLiteral("true" ) : QStringLiteral("false" ); |
1579 | case Binding::Type_Number: |
1580 | return QString::number(bindingValueAsNumber(binding), format: 'g', precision: QLocale::FloatingPointShortest); |
1581 | case Binding::Type_Invalid: |
1582 | return QString(); |
1583 | case Binding::Type_TranslationById: |
1584 | case Binding::Type_Translation: |
1585 | return stringAt(index: data->translations()[binding->value.translationDataIndex].stringIndex); |
1586 | default: |
1587 | break; |
1588 | } |
1589 | return QString(); |
1590 | } |
1591 | |
1592 | QString bindingValueAsScriptString(const CompiledData::Binding *binding) const |
1593 | { |
1594 | return (binding->type() == CompiledData::Binding::Type_String) |
1595 | ? CompiledData::Binding::escapedString(string: stringAt(index: binding->stringIndex)) |
1596 | : bindingValueAsString(binding); |
1597 | } |
1598 | |
1599 | double bindingValueAsNumber(const CompiledData::Binding *binding) const |
1600 | { |
1601 | if (binding->type() != CompiledData::Binding::Type_Number) |
1602 | return 0.0; |
1603 | return constants[binding->value.constantValueIndex].doubleValue(); |
1604 | } |
1605 | |
1606 | private: |
1607 | QString m_fileName; // initialized from data->sourceFileIndex |
1608 | QString m_finalUrlString; // initialized from data->finalUrlIndex |
1609 | |
1610 | Heap::Module *m_module = nullptr; |
1611 | }; |
1612 | |
1613 | class SaveableUnitPointer |
1614 | { |
1615 | Q_DISABLE_COPY_MOVE(SaveableUnitPointer) |
1616 | public: |
1617 | SaveableUnitPointer(const Unit *unit, quint32 temporaryFlags = Unit::StaticData) : |
1618 | unit(unit), |
1619 | temporaryFlags(temporaryFlags) |
1620 | { |
1621 | } |
1622 | |
1623 | ~SaveableUnitPointer() = default; |
1624 | |
1625 | template<typename Char> |
1626 | bool saveToDisk(const std::function<bool(const Char *, quint32)> &writer) const |
1627 | { |
1628 | const quint32_le oldFlags = mutableFlags(); |
1629 | auto cleanup = qScopeGuard([this, oldFlags]() { mutableFlags() = oldFlags; }); |
1630 | mutableFlags() |= temporaryFlags; |
1631 | return writer(data<Char>(), size()); |
1632 | } |
1633 | |
1634 | static bool writeDataToFile(const QString &outputFileName, const char *data, quint32 size, |
1635 | QString *errorString) |
1636 | { |
1637 | #if QT_CONFIG(temporaryfile) |
1638 | QSaveFile cacheFile(outputFileName); |
1639 | if (!cacheFile.open(flags: QIODevice::WriteOnly | QIODevice::Truncate) |
1640 | || cacheFile.write(data, len: size) != size |
1641 | || !cacheFile.commit()) { |
1642 | *errorString = cacheFile.errorString(); |
1643 | return false; |
1644 | } |
1645 | |
1646 | errorString->clear(); |
1647 | return true; |
1648 | #else |
1649 | Q_UNUSED(outputFileName); |
1650 | *errorString = QStringLiteral("features.temporaryfile is disabled." ); |
1651 | return false; |
1652 | #endif |
1653 | } |
1654 | |
1655 | private: |
1656 | const Unit *unit; |
1657 | quint32 temporaryFlags; |
1658 | |
1659 | quint32_le &mutableFlags() const |
1660 | { |
1661 | return const_cast<Unit *>(unit)->flags; |
1662 | } |
1663 | |
1664 | template<typename Char> |
1665 | const Char *data() const |
1666 | { |
1667 | Q_STATIC_ASSERT(sizeof(Char) == 1); |
1668 | const Char *dataPtr; |
1669 | memcpy(&dataPtr, &unit, sizeof(dataPtr)); |
1670 | return dataPtr; |
1671 | } |
1672 | |
1673 | quint32 size() const |
1674 | { |
1675 | return unit->unitSize; |
1676 | } |
1677 | }; |
1678 | |
1679 | |
1680 | } // CompiledData namespace |
1681 | } // QV4 namespace |
1682 | |
1683 | Q_DECLARE_OPERATORS_FOR_FLAGS(QV4::CompiledData::ParameterType::Flags); |
1684 | Q_DECLARE_TYPEINFO(QV4::CompiledData::JSClassMember, Q_PRIMITIVE_TYPE); |
1685 | |
1686 | QT_END_NAMESPACE |
1687 | |
1688 | #endif |
1689 | |