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 { TableIteratorTableIterator110 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 LocationLocation129 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 RegExpRegExp154 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 LookupLookup173 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 JSClassMemberJSClassMember185 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 calculateSizeJSClass194 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 calculateSizeString215 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 localsTableBlock245 const quint32_le *localsTable() const { return reinterpret_cast<const quint32_le *>(reinterpret_cast<const char *>(this) + localsOffset); } 246 calculateSizeBlock247 static int calculateSize(int nLocals) { 248 int trailingData = nLocals*sizeof (quint32); 249 size_t size = align(align(sizeof(Block)) + size_t(trailingData)); 250 Q_ASSERT(size < INT_MAX); 251 return int(size); 252 } 253 alignBlock254 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; lineNumberOffsetFunction305 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 labelInfosOffsetFunction316 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 formalsTableFunction325 const Parameter *formalsTable() const { return reinterpret_cast<const Parameter *>(reinterpret_cast<const char *>(this) + formalsOffset); } localsTableFunction326 const quint32_le *localsTable() const { return reinterpret_cast<const quint32_le *>(reinterpret_cast<const char *>(this) + localsOffset); } lineNumberTableFunction327 const CodeOffsetToLine *lineNumberTable() const { return reinterpret_cast<const CodeOffsetToLine *>(reinterpret_cast<const char *>(this) + lineNumberOffset()); } 328 329 // --- QQmlPropertyCacheCreator interface formalsBeginFunction330 const Parameter *formalsBegin() const { return formalsTable(); } formalsEndFunction331 const Parameter *formalsEnd() const { return formalsTable() + nFormals; } 332 // --- 333 labelInfoTableFunction334 const quint32_le *labelInfoTable() const { return reinterpret_cast<const quint32_le *>(reinterpret_cast<const char *>(this) + labelInfosOffset()); } 335 codeFunction336 const char *code() const { return reinterpret_cast<const char *>(this) + codeOffset; } 337 calculateSizeFunction338 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(align(sizeof(Function)) + size_t(trailingData)) + align(codeSize); 342 Q_ASSERT(size < INT_MAX); 343 return int(size); 344 } 345 alignFunction346 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 methodTableClass374 const Method *methodTable() const { return reinterpret_cast<const Method *>(reinterpret_cast<const char *>(this) + methodTableOffset); } 375 calculateSizeClass376 static int calculateSize(int nStaticMethods, int nMethods) { 377 int trailingData = (nStaticMethods + nMethods) * sizeof(Method); 378 size_t size = align(sizeof(Class) + trailingData); 379 Q_ASSERT(size < INT_MAX); 380 return int(size); 381 } 382 alignClass383 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 calculateSizeTemplateObject393 static int calculateSize(int size) { 394 int trailingData = 2 * size * sizeof(quint32_le); 395 size_t s = align(sizeof(TemplateObject) + trailingData); 396 Q_ASSERT(s < INT_MAX); 397 return int(s); 398 } 399 alignTemplateObject400 static size_t align(size_t a) { 401 return (a + 7) & ~size_t(7); 402 } 403 stringTableTemplateObject404 const quint32_le *stringTable() const { 405 return reinterpret_cast<const quint32_le *>(reinterpret_cast<const char *>(this + 1)); 406 } 407 stringIndexAtTemplateObject408 uint stringIndexAt(uint i) const { 409 return stringTable()[i]; 410 } rawStringIndexAtTemplateObject411 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 commentIndex; 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 isValueBindingBinding495 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 isValueBindingNoAliasBinding506 bool isValueBindingNoAlias() const { return isValueBinding() && !(flags & IsBindingToAlias); } isValueBindingToAliasBinding507 bool isValueBindingToAlias() const { return isValueBinding() && (flags & IsBindingToAlias); } 508 isSignalHandlerBinding509 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 isAttachedPropertyBinding520 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 isGroupPropertyBinding531 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 isFunctionExpressionBinding542 bool isFunctionExpression() const { return (flags & IsFunctionExpression); } 543 544 //reverse of Lexer::singleEscape() escapedStringBinding545 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 isTranslationBindingBinding587 bool isTranslationBinding() const { return type == Type_Translation || type == Type_TranslationById; } evaluatesToStringBinding588 bool evaluatesToString() const { return type == Type_String || isTranslationBinding(); } 589 valueAsBooleanBinding590 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 enumValueAtEnum624 const EnumValue *enumValueAt(int idx) const { 625 return reinterpret_cast<const EnumValue*>(this + 1) + idx; 626 } 627 calculateSizeEnum628 static int calculateSize(int nEnumValues) { 629 return (sizeof(Enum) 630 + nEnumValues * sizeof(EnumValue) 631 + 7) & ~0x7; 632 } 633 634 // --- QQmlPropertyCacheCreatorInterface enumValuesBeginEnum635 const EnumValue *enumValuesBegin() const { return enumValueAt(0); } enumValuesEndEnum636 const EnumValue *enumValuesEnd() const { return enumValueAt(nEnumValues); } enumValueCountEnum637 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 parameterAtSignal649 const Parameter *parameterAt(int idx) const { 650 return reinterpret_cast<const Parameter*>(this + 1) + idx; 651 } 652 calculateSizeSignal653 static int calculateSize(int nParameters) { 654 return (sizeof(Signal) 655 + nParameters * sizeof(Parameter) 656 + 7) & ~0x7; 657 } 658 659 // --- QQmlPropertyCacheCceatorInterface parametersBeginSignal660 const Parameter *parametersBegin() const { return parameterAt(0); } parametersEndSignal661 const Parameter *parametersEnd() const { return parameterAt(nParameters); } parameterCountSignal662 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 setBuiltinTypeProperty680 void setBuiltinType(BuiltinType t) 681 { 682 builtinTypeOrTypeNameIndex = static_cast<quint32>(t); 683 isBuiltinType = true; 684 } builtinTypeProperty685 BuiltinType builtinType() const { 686 if (isBuiltinType) 687 return static_cast<BuiltinType>(quint32(builtinTypeOrTypeNameIndex)); 688 return BuiltinType::InvalidBuiltin; 689 } setCustomTypeProperty690 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 RequiredPropertyExtraData { 699 quint32_le nameIndex; 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 isObjectAliasAlias727 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 offsetToRequiredPropertyExtraData; 775 quint16_le nRequiredPropertyExtraData; 776 // Function[] 777 // Property[] 778 // Signal[] 779 // Binding[] 780 // InlineComponent[] 781 // RequiredPropertyExtraData[] 782 calculateSizeExcludingSignalsAndEnumsObject783 static int calculateSizeExcludingSignalsAndEnums(int nFunctions, int nProperties, int nAliases, int nEnums, int nSignals, int nBindings, int nNamedObjectsInComponent, int nInlineComponents, int nRequiredPropertyExtraData) 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 functionOffsetTableObject799 const quint32_le *functionOffsetTable() const 800 { 801 return reinterpret_cast<const quint32_le*>(reinterpret_cast<const char *>(this) + offsetToFunctions); 802 } 803 propertyTableObject804 const Property *propertyTable() const 805 { 806 return reinterpret_cast<const Property*>(reinterpret_cast<const char *>(this) + offsetToProperties); 807 } 808 aliasTableObject809 const Alias *aliasTable() const 810 { 811 return reinterpret_cast<const Alias*>(reinterpret_cast<const char *>(this) + offsetToAliases); 812 } 813 bindingTableObject814 const Binding *bindingTable() const 815 { 816 return reinterpret_cast<const Binding*>(reinterpret_cast<const char *>(this) + offsetToBindings); 817 } 818 enumAtObject819 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 signalAtObject826 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 inlineComponentAtObject833 const InlineComponent *inlineComponentAt(int idx) const 834 { 835 return inlineComponentTable() + idx; 836 } 837 namedObjectsInComponentTableObject838 const quint32_le *namedObjectsInComponentTable() const 839 { 840 return reinterpret_cast<const quint32_le*>(reinterpret_cast<const char *>(this) + offsetToNamedObjectsInComponent); 841 } 842 inlineComponentTableObject843 const InlineComponent *inlineComponentTable() const 844 { 845 return reinterpret_cast<const InlineComponent*>(reinterpret_cast<const char *>(this) + offsetToInlineComponents); 846 } 847 requiredPropertyExtraDataAtObject848 const RequiredPropertyExtraData *requiredPropertyExtraDataAt(int idx) const 849 { 850 return requiredPropertyExtraDataTable() + idx; 851 } 852 requiredPropertyExtraDataTableObject853 const RequiredPropertyExtraData *requiredPropertyExtraDataTable() const 854 { 855 return reinterpret_cast<const RequiredPropertyExtraData*>(reinterpret_cast<const char *>(this) + offsetToRequiredPropertyExtraData); 856 } 857 858 // --- QQmlPropertyCacheCreator interface propertyCountObject859 int propertyCount() const { return nProperties; } aliasCountObject860 int aliasCount() const { return nAliases; } enumCountObject861 int enumCount() const { return nEnums; } signalCountObject862 int signalCount() const { return nSignals; } functionCountObject863 int functionCount() const { return nFunctions; } 864 bindingsBeginObject865 const Binding *bindingsBegin() const { return bindingTable(); } bindingsEndObject866 const Binding *bindingsEnd() const { return bindingTable() + nBindings; } 867 propertiesBeginObject868 const Property *propertiesBegin() const { return propertyTable(); } propertiesEndObject869 const Property *propertiesEnd() const { return propertyTable() + nProperties; } 870 aliasesBeginObject871 const Alias *aliasesBegin() const { return aliasTable(); } aliasesEndObject872 const Alias *aliasesEnd() const { return aliasTable() + nAliases; } 873 874 typedef TableIterator<Enum, Object, &Object::enumAt> EnumIterator; enumsBeginObject875 EnumIterator enumsBegin() const { return EnumIterator(this, 0); } enumsEndObject876 EnumIterator enumsEnd() const { return EnumIterator(this, nEnums); } 877 878 typedef TableIterator<Signal, Object, &Object::signalAt> SignalIterator; signalsBeginObject879 SignalIterator signalsBegin() const { return SignalIterator(this, 0); } signalsEndObject880 SignalIterator signalsEnd() const { return SignalIterator(this, nSignals); } 881 882 typedef TableIterator<InlineComponent, Object, &Object::inlineComponentAt> InlineComponentIterator; inlineComponentsBeginObject883 InlineComponentIterator inlineComponentsBegin() const {return InlineComponentIterator(this, 0);} inlineComponentsEndObject884 InlineComponentIterator inlineComponentsEnd() const {return InlineComponentIterator(this, nInlineComponents);} 885 886 typedef TableIterator<RequiredPropertyExtraData, Object, &Object::requiredPropertyExtraDataAt> RequiredPropertyExtraDataIterator; requiredPropertyExtraDataBeginObject887 RequiredPropertyExtraDataIterator requiredPropertyExtraDataBegin() const {return RequiredPropertyExtraDataIterator(this, 0); }; requiredPropertyExtraDataEndObject888 RequiredPropertyExtraDataIterator requiredPropertyExtraDataEnd() const {return RequiredPropertyExtraDataIterator(this, nRequiredPropertyExtraData); }; 889 namedObjectsInComponentCountObject890 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 ImportImport913 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 importAtQmlUnit924 const Import *importAt(int idx) const { 925 return reinterpret_cast<const Import*>((reinterpret_cast<const char *>(this)) + offsetToImports + idx * sizeof(Import)); 926 } 927 objectAtQmlUnit928 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 qmlUnitUnit1001 const QmlUnit *qmlUnit() const { 1002 return reinterpret_cast<const QmlUnit *>(reinterpret_cast<const char *>(this) + offsetToQmlUnit); 1003 } 1004 qmlUnitUnit1005 QmlUnit *qmlUnit() { 1006 return reinterpret_cast<QmlUnit *>(reinterpret_cast<char *>(this) + offsetToQmlUnit); 1007 } 1008 isSingletonUnit1009 bool isSingleton() const { 1010 return flags & Unit::IsSingleton; 1011 } 1012 /* end QML specific fields*/ 1013 stringAtInternalUnit1014 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 = { 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 functionOffsetTableUnit1038 const quint32_le *functionOffsetTable() const { return reinterpret_cast<const quint32_le*>((reinterpret_cast<const char *>(this)) + offsetToFunctionTable); } classOffsetTableUnit1039 const quint32_le *classOffsetTable() const { return reinterpret_cast<const quint32_le*>((reinterpret_cast<const char *>(this)) + offsetToClassTable); } templateObjectOffsetTableUnit1040 const quint32_le *templateObjectOffsetTable() const { return reinterpret_cast<const quint32_le*>((reinterpret_cast<const char *>(this)) + offsetToTemplateObjectTable); } blockOffsetTableUnit1041 const quint32_le *blockOffsetTable() const { return reinterpret_cast<const quint32_le*>((reinterpret_cast<const char *>(this)) + offsetToBlockTable); } 1042 functionAtUnit1043 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 classAtUnit1049 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 templateObjectAtUnit1055 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 blockAtUnit1061 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 lookupTableUnit1067 const Lookup *lookupTable() const { return reinterpret_cast<const Lookup*>(reinterpret_cast<const char *>(this) + offsetToLookupTable); } regexpAtUnit1068 const RegExp *regexpAt(int index) const { 1069 return reinterpret_cast<const RegExp*>(reinterpret_cast<const char *>(this) + offsetToRegexpTable + index * sizeof(RegExp)); 1070 } constantsUnit1071 const quint64_le *constants() const { 1072 return reinterpret_cast<const quint64_le*>(reinterpret_cast<const char *>(this) + offsetToConstantTable); 1073 } 1074 jsClassAtUnit1075 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 translationsUnit1084 const TranslationData *translations() const { 1085 return reinterpret_cast<const TranslationData *>(reinterpret_cast<const char *>(this) + offsetToTranslationTable); 1086 } 1087 importEntryTableUnit1088 const ImportEntry *importEntryTable() const { return reinterpret_cast<const ImportEntry *>(reinterpret_cast<const char *>(this) + offsetToImportEntryTable); } localExportEntryTableUnit1089 const ExportEntry *localExportEntryTable() const { return reinterpret_cast<const ExportEntry *>(reinterpret_cast<const char *>(this) + offsetToLocalExportEntryTable); } indirectExportEntryTableUnit1090 const ExportEntry *indirectExportEntryTable() const { return reinterpret_cast<const ExportEntry *>(reinterpret_cast<const char *>(this) + offsetToIndirectExportEntryTable); } starExportEntryTableUnit1091 const ExportEntry *starExportEntryTable() const { return reinterpret_cast<const ExportEntry *>(reinterpret_cast<const char *>(this) + offsetToStarExportEntryTable); } 1092 moduleRequestTableUnit1093 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 { TypeReferenceTypeReference1100 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 { addTypeReferenceMap1113 TypeReference &add(int nameIndex, const Location &loc) { 1114 Iterator it = find(nameIndex); 1115 if (it != end()) 1116 return *it; 1117 return *insert(nameIndex, loc); 1118 } 1119 1120 template <typename CompiledObject> collectFromObjectTypeReferenceMap1121 void collectFromObject(const CompiledObject *obj) 1122 { 1123 if (obj->inheritedTypeNameIndex != 0) { 1124 TypeReference &r = this->add(obj->inheritedTypeNameIndex, 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(prop->builtinTypeOrTypeNameIndex, 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(binding->propertyNameIndex, binding->location); 1143 } 1144 1145 auto ic = obj->inlineComponentsBegin(); 1146 auto const icEnd = obj->inlineComponentsEnd(); 1147 for (; ic != icEnd; ++ic) { 1148 this->add(ic->nameIndex, ic->location); 1149 } 1150 } 1151 1152 template <typename Iterator> collectFromObjectsTypeReferenceMap1153 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 CompilationUnitBaseCompilationUnitBase1171 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, nullptr, fileName, finalUrlString); 1219 } 1220 ~CompilationUnitCompilationUnit1221 ~CompilationUnit() 1222 { 1223 if (data) { 1224 if (data->qmlUnit() != qmlData) 1225 free(const_cast<QmlUnit *>(qmlData)); 1226 qmlData = nullptr; 1227 1228 if (!(data->flags & QV4::CompiledData::Unit::StaticData)) 1229 free(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 CompilationUnitCompilationUnit1241 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=(std::move(other)); 1262 } 1263 return *this; 1264 } 1265 unitDataCompilationUnit1266 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(data->sourceFileIndex); 1295 m_finalUrlString = !finalUrlString.isEmpty() ? finalUrlString : stringAt(data->finalUrlIndex); 1296 } 1297 stringAtCompilationUnit1298 QString stringAt(int index) const 1299 { 1300 if (uint(index) >= data->stringTableSize) 1301 return dynamicStrings.at(index - data->stringTableSize); 1302 return data->stringAtInternal(index); 1303 } 1304 fileNameCompilationUnit1305 QString fileName() const { return m_fileName; } finalUrlStringCompilationUnit1306 QString finalUrlString() const { return m_finalUrlString; } 1307 moduleCompilationUnit1308 Heap::Module *module() const { return m_module; } setModuleCompilationUnit1309 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 { Q_DISABLE_COPY_MOVE(SaveableUnitPointer)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> saveToDisk(const std::function<bool (const Char *,quint32)> & writer)1331 bool saveToDisk(const std::function<bool(const Char *, quint32)> &writer) const 1332 { 1333 auto cleanup = qScopeGuard([this]() { mutableFlags() ^= temporaryFlags; }); 1334 mutableFlags() |= temporaryFlags; 1335 return writer(data<Char>(), size()); 1336 } 1337 writeDataToFile(const QString & outputFileName,const char * data,quint32 size,QString * errorString)1338 static bool writeDataToFile(const QString &outputFileName, const char *data, quint32 size, 1339 QString *errorString) 1340 { 1341 #if QT_CONFIG(temporaryfile) 1342 QSaveFile cacheFile(outputFileName); 1343 if (!cacheFile.open(QIODevice::WriteOnly | QIODevice::Truncate) 1344 || cacheFile.write(data, size) != size 1345 || !cacheFile.commit()) { 1346 *errorString = cacheFile.errorString(); 1347 return false; 1348 } 1349 1350 errorString->clear(); 1351 return true; 1352 #else 1353 Q_UNUSED(outputFileName) 1354 *errorString = QStringLiteral("features.temporaryfile is disabled."); 1355 return false; 1356 #endif 1357 } 1358 1359 private: 1360 const Unit *unit; 1361 quint32 temporaryFlags; 1362 mutableFlags()1363 quint32_le &mutableFlags() const 1364 { 1365 return const_cast<Unit *>(unit)->flags; 1366 } 1367 1368 template<typename Char> data()1369 const Char *data() const 1370 { 1371 Q_STATIC_ASSERT(sizeof(Char) == 1); 1372 const Char *dataPtr; 1373 memcpy(&dataPtr, &unit, sizeof(dataPtr)); 1374 return dataPtr; 1375 } 1376 size()1377 quint32 size() const 1378 { 1379 return unit->unitSize; 1380 } 1381 }; 1382 1383 1384 } // CompiledData namespace 1385 } // QV4 namespace 1386 1387 Q_DECLARE_TYPEINFO(QV4::CompiledData::JSClassMember, Q_PRIMITIVE_TYPE); 1388 1389 QT_END_NAMESPACE 1390 1391 #endif 1392