diff options
Diffstat (limited to 'src/qml/compiler/qv4compileddata_p.h')
-rw-r--r-- | src/qml/compiler/qv4compileddata_p.h | 580 |
1 files changed, 437 insertions, 143 deletions
diff --git a/src/qml/compiler/qv4compileddata_p.h b/src/qml/compiler/qv4compileddata_p.h index 8c617875e0..90cbe04505 100644 --- a/src/qml/compiler/qv4compileddata_p.h +++ b/src/qml/compiler/qv4compileddata_p.h @@ -60,11 +60,26 @@ #include <private/qv4executableallocator_p.h> #include <private/qqmlrefcount_p.h> #include <private/qqmlnullablevalue_p.h> +#include <private/qv4identifier_p.h> +#include <private/qflagpointer_p.h> +#include <private/qjson_p.h> +#ifndef V4_BOOTSTRAP +#include <private/qqmltypenamecache_p.h> +#include <private/qqmlpropertycache_p.h> +#endif QT_BEGIN_NAMESPACE +// Bump this whenever the compiler data structures change in an incompatible way. +#define QV4_DATA_STRUCTURE_VERSION 0x07 + +class QIODevice; class QQmlPropertyCache; class QQmlPropertyData; +class QQmlTypeNameCache; +class QQmlScriptData; +class QQmlType; +class QQmlEngine; namespace QmlIR { struct Document; @@ -76,25 +91,49 @@ struct Function; } struct Function; +class EvalISelFactory; +class CompilationUnitMapper; namespace CompiledData { +typedef QJsonPrivate::q_littleendian<qint16> LEInt16; +typedef QJsonPrivate::q_littleendian<quint16> LEUInt16; +typedef QJsonPrivate::q_littleendian<quint32> LEUInt32; +typedef QJsonPrivate::q_littleendian<qint32> LEInt32; +typedef QJsonPrivate::q_littleendian<quint64> LEUInt64; +typedef QJsonPrivate::q_littleendian<qint64> LEInt64; + struct String; struct Function; struct Lookup; struct RegExp; struct Unit; +template <typename ItemType, typename Container, const ItemType *(Container::*IndexedGetter)(int index) const> +struct TableIterator +{ + TableIterator(const Container *container, int index) : container(container), index(index) {} + const Container *container; + int index; + + const ItemType *operator->() { return (container->*IndexedGetter)(index); } + void operator++() { ++index; } + bool operator==(const TableIterator &rhs) const { return index == rhs.index; } + bool operator!=(const TableIterator &rhs) const { return index != rhs.index; } +}; + #if defined(Q_CC_MSVC) || defined(Q_CC_GNU) #pragma pack(push, 1) #endif struct Location { - qint32 line; - qint32 column; + union { + QJsonPrivate::qle_bitfield<0, 20> line; + QJsonPrivate::qle_bitfield<20, 12> column; + }; - Location(): line(-1), column(-1) {} + Location() { line = 0; column = 0; } inline bool operator<(const Location &other) const { return line < other.line || @@ -104,20 +143,22 @@ struct Location struct RegExp { - enum Flags { + enum Flags : unsigned int { RegExp_Global = 0x01, RegExp_IgnoreCase = 0x02, RegExp_Multiline = 0x04 }; - quint32 flags; - quint32 stringIndex; + union { + QJsonPrivate::qle_bitfield<0, 4> flags; + QJsonPrivate::qle_bitfield<4, 28> stringIndex; + }; - static int calculateSize() { return sizeof(RegExp); } + RegExp() { flags = 0; stringIndex = 0; } }; struct Lookup { - enum Type { + enum Type : unsigned int { Type_Getter = 0x0, Type_Setter = 0x1, Type_GlobalGetter = 2, @@ -125,21 +166,27 @@ struct Lookup Type_IndexedSetter = 4 }; - quint32 type_and_flags; - quint32 nameIndex; + union { + QJsonPrivate::qle_bitfield<0, 4> type_and_flags; + QJsonPrivate::qle_bitfield<4, 28> nameIndex; + }; - static int calculateSize() { return sizeof(Lookup); } + Lookup() { type_and_flags = 0; nameIndex = 0; } }; struct JSClassMember { - uint nameOffset : 31; - uint isAccessor : 1; + union { + QJsonPrivate::qle_bitfield<0, 31> nameOffset; + QJsonPrivate::qle_bitfield<31, 1> isAccessor; + }; + + JSClassMember() { nameOffset = 0; isAccessor = 0; } }; struct JSClass { - uint nMembers; + LEUInt32 nMembers; // JSClassMember[nMembers] static int calculateSize(int nMembers) { return (sizeof(JSClass) + nMembers * sizeof(JSClassMember) + 7) & ~7; } @@ -147,8 +194,7 @@ struct JSClass struct String { - quint32 flags; // isArrayIndex - qint32 size; + LEInt32 size; // uint16 strdata[] static int calculateSize(const QString &str) { @@ -156,9 +202,11 @@ struct String } }; +// Function is aligned on an 8-byte boundary to make sure there are no bus errors or penalties +// for unaligned access. The ordering of the fields is also from largest to smallest. struct Function { - enum Flags { + enum Flags : unsigned int { HasDirectEval = 0x1, UsesArgumentsObject = 0x2, IsStrict = 0x4, @@ -166,24 +214,26 @@ struct Function HasCatchOrWith = 0x10 }; - quint32 index; // in CompilationUnit's function table - quint32 nameIndex; - qint64 flags; - quint32 nFormals; - quint32 formalsOffset; - quint32 nLocals; - quint32 localsOffset; - quint32 nInnerFunctions; - quint32 innerFunctionsOffset; + // Absolute offset into file where the code for this function is located. Only used when the function + // is serialized. + LEUInt64 codeOffset; + LEUInt64 codeSize; + + LEUInt32 nameIndex; + LEUInt32 nFormals; + LEUInt32 formalsOffset; + LEUInt32 nLocals; + LEUInt32 localsOffset; + LEUInt32 nInnerFunctions; Location location; // Qml Extensions Begin - quint32 nDependingIdObjects; - quint32 dependingIdObjectsOffset; // Array of resolved ID objects - quint32 nDependingContextProperties; - quint32 dependingContextPropertiesOffset; // Array of int pairs (property index and notify index) - quint32 nDependingScopeProperties; - quint32 dependingScopePropertiesOffset; // Array of int pairs (property index and notify index) + LEUInt32 nDependingIdObjects; + LEUInt32 dependingIdObjectsOffset; // Array of resolved ID objects + LEUInt32 nDependingContextProperties; + LEUInt32 dependingContextPropertiesOffset; // Array of int pairs (property index and notify index) + LEUInt32 nDependingScopeProperties; + LEUInt32 dependingScopePropertiesOffset; // Array of int pairs (property index and notify index) // Qml Extensions End // quint32 formalsIndex[nFormals] @@ -191,11 +241,19 @@ struct Function // quint32 offsetForInnerFunctions[nInnerFunctions] // Function[nInnerFunctions] - const quint32 *formalsTable() const { return reinterpret_cast<const quint32 *>(reinterpret_cast<const char *>(this) + formalsOffset); } - const quint32 *localsTable() const { return reinterpret_cast<const quint32 *>(reinterpret_cast<const char *>(this) + localsOffset); } - const quint32 *qmlIdObjectDependencyTable() const { return reinterpret_cast<const quint32 *>(reinterpret_cast<const char *>(this) + dependingIdObjectsOffset); } - const quint32 *qmlContextPropertiesDependencyTable() const { return reinterpret_cast<const quint32 *>(reinterpret_cast<const char *>(this) + dependingContextPropertiesOffset); } - const quint32 *qmlScopePropertiesDependencyTable() const { return reinterpret_cast<const quint32 *>(reinterpret_cast<const char *>(this) + dependingScopePropertiesOffset); } + // Keep all unaligned data at the end + quint8 flags; + + const LEUInt32 *formalsTable() const { return reinterpret_cast<const LEUInt32 *>(reinterpret_cast<const char *>(this) + formalsOffset); } + const LEUInt32 *localsTable() const { return reinterpret_cast<const LEUInt32 *>(reinterpret_cast<const char *>(this) + localsOffset); } + const LEUInt32 *qmlIdObjectDependencyTable() const { return reinterpret_cast<const LEUInt32 *>(reinterpret_cast<const char *>(this) + dependingIdObjectsOffset); } + const LEUInt32 *qmlContextPropertiesDependencyTable() const { return reinterpret_cast<const LEUInt32 *>(reinterpret_cast<const char *>(this) + dependingContextPropertiesOffset); } + const LEUInt32 *qmlScopePropertiesDependencyTable() const { return reinterpret_cast<const LEUInt32 *>(reinterpret_cast<const char *>(this) + dependingScopePropertiesOffset); } + + // --- QQmlPropertyCacheCreator interface + const LEUInt32 *formalsBegin() const { return formalsTable(); } + const LEUInt32 *formalsEnd() const { return formalsTable() + nFormals; } + // --- inline bool hasQmlDependencies() const { return nDependingIdObjects > 0 || nDependingContextProperties > 0 || nDependingScopeProperties > 0; } @@ -207,15 +265,15 @@ struct Function // Qml data structures struct Q_QML_EXPORT TranslationData { - quint32 commentIndex; - int number; + LEUInt32 commentIndex; + LEInt32 number; }; struct Q_QML_PRIVATE_EXPORT Binding { - quint32 propertyNameIndex; + LEUInt32 propertyNameIndex; - enum ValueType { + enum ValueType : unsigned int { Type_Invalid, Type_Boolean, Type_Number, @@ -228,26 +286,30 @@ struct Q_QML_PRIVATE_EXPORT Binding Type_GroupProperty }; - enum Flags { + enum Flags : unsigned int { IsSignalHandlerExpression = 0x1, IsSignalHandlerObject = 0x2, IsOnAssignment = 0x4, InitializerForReadOnlyDeclaration = 0x8, IsResolvedEnum = 0x10, IsListItem = 0x20, - IsBindingToAlias = 0x40 + IsBindingToAlias = 0x40, + IsDeferredBinding = 0x80, + IsCustomParserBinding = 0x100, }; - quint32 flags : 16; - quint32 type : 16; + union { + QJsonPrivate::qle_bitfield<0, 16> flags; + QJsonPrivate::qle_bitfield<16, 16> type; + }; union { bool b; - double d; - quint32 compiledScriptIndex; // used when Type_Script - quint32 objectIndex; + quint64 doubleValue; // do not access directly, needs endian protected access + LEUInt32 compiledScriptIndex; // used when Type_Script + LEUInt32 objectIndex; TranslationData translationData; // used when Type_Translation } value; - quint32 stringIndex; // Set for Type_String, Type_Translation and Type_Script (the latter because of script strings) + LEUInt32 stringIndex; // Set for Type_String, Type_Translation and Type_Script (the latter because of script strings) Location location; Location valueLocation; @@ -307,11 +369,20 @@ struct Q_QML_PRIVATE_EXPORT Binding QString valueAsScriptString(const Unit *unit) const; double valueAsNumber() const { - if (type == Type_Number) - return value.d; - return 0.0; - + if (type != Type_Number) + return 0.0; + quint64 intval = qFromLittleEndian<quint64>(value.doubleValue); + double d; + memcpy(&d, &intval, sizeof(double)); + return d; } + void setNumberValueInternal(double d) + { + quint64 intval; + memcpy(&intval, &d, sizeof(double)); + value.doubleValue = qToLittleEndian<quint64>(intval); + } + bool valueAsBoolean() const { if (type == Type_Boolean) @@ -323,17 +394,16 @@ struct Q_QML_PRIVATE_EXPORT Binding struct Parameter { - quint32 nameIndex; - quint32 type; - quint32 customTypeNameIndex; - quint32 reserved; + LEUInt32 nameIndex; + LEUInt32 type; + LEUInt32 customTypeNameIndex; Location location; }; struct Signal { - quint32 nameIndex; - quint32 nParameters; + LEUInt32 nameIndex; + LEUInt32 nParameters; Location location; // Parameter parameters[1]; @@ -346,47 +416,95 @@ struct Signal + nParameters * sizeof(Parameter) + 7) & ~0x7; } + + // --- QQmlPropertyCacheCceatorInterface + const Parameter *parametersBegin() const { return parameterAt(0); } + const Parameter *parametersEnd() const { return parameterAt(nParameters); } + int parameterCount() const { return nParameters; } + // --- }; struct Property { - enum Type { Var = 0, Variant, Int, Bool, Real, String, Url, Color, + enum Type : unsigned int { Var = 0, Variant, Int, Bool, Real, String, Url, Color, Font, Time, Date, DateTime, Rect, Point, Size, Vector2D, Vector3D, Vector4D, Matrix4x4, Quaternion, - Alias, Custom, CustomList }; + Custom, CustomList }; - enum Flags { + enum Flags : unsigned int { IsReadOnly = 0x1 }; - quint32 nameIndex; - quint32 type; + LEUInt32 nameIndex; union { - quint32 customTypeNameIndex; // If type >= Custom - quint32 aliasIdValueIndex; // If type == Alias + QJsonPrivate::qle_bitfield<0, 31> type; + QJsonPrivate::qle_bitfield<31, 1> flags; // readonly }; - quint32 aliasPropertyValueIndex; - quint32 flags; // readonly + LEUInt32 customTypeNameIndex; // If type >= Custom Location location; - Location aliasLocation; // If type == Alias +}; + +struct Alias { + enum Flags : unsigned int { + IsReadOnly = 0x1, + Resolved = 0x2, + AliasPointsToPointerObject = 0x4 + }; + union { + QJsonPrivate::qle_bitfield<0, 29> nameIndex; + QJsonPrivate::qle_bitfield<29, 3> flags; + }; + union { + LEUInt32 idIndex; // string index + QJsonPrivate::qle_bitfield<0, 31> targetObjectId; // object id index (in QQmlContextData::idValues) + QJsonPrivate::qle_bitfield<31, 1> aliasToLocalAlias; + }; + union { + LEUInt32 propertyNameIndex; // string index + LEInt32 encodedMetaPropertyIndex; + LEUInt32 localAliasIndex; // index in list of aliases local to the object (if targetObjectId == objectId) + }; + Location location; + Location referenceLocation; + + bool isObjectAlias() const { + Q_ASSERT(flags & Resolved); + return encodedMetaPropertyIndex == -1; + } }; struct Object { + enum Flags : unsigned int { + NoFlag = 0x0, + IsComponent = 0x1, // object was identified to be an explicit or implicit component boundary + HasDeferredBindings = 0x2, // any of the bindings are deferred + HasCustomParserBindings = 0x4 + }; + // Depending on the use, this may be the type name to instantiate before instantiating this // object. For grouped properties the type name will be empty and for attached properties // it will be the name of the attached type. - quint32 inheritedTypeNameIndex; - quint32 idIndex; - qint32 indexOfDefaultProperty; // -1 means no default property declared in this object - quint32 nFunctions; - quint32 offsetToFunctions; - quint32 nProperties; - quint32 offsetToProperties; - quint32 nSignals; - quint32 offsetToSignals; // which in turn will be a table with offsets to variable-sized Signal objects - quint32 nBindings; - quint32 offsetToBindings; + LEUInt32 inheritedTypeNameIndex; + LEUInt32 idNameIndex; + union { + QJsonPrivate::qle_bitfield<0, 15> flags; + QJsonPrivate::qle_bitfield<15, 1> defaultPropertyIsAlias; + QJsonPrivate::qle_signedbitfield<16, 16> id; + }; + LEInt32 indexOfDefaultPropertyOrAlias; // -1 means no default property declared in this object + LEUInt32 nFunctions; + LEUInt32 offsetToFunctions; + LEUInt32 nProperties; + LEUInt32 offsetToProperties; + LEUInt32 nAliases; + LEUInt32 offsetToAliases; + LEUInt32 nSignals; + LEUInt32 offsetToSignals; // which in turn will be a table with offsets to variable-sized Signal objects + LEUInt32 nBindings; + LEUInt32 offsetToBindings; + LEUInt32 nNamedObjectsInComponent; + LEUInt32 offsetToNamedObjectsInComponent; Location location; Location locationOfIdProperty; // Function[] @@ -394,20 +512,22 @@ struct Object // Signal[] // Binding[] - static int calculateSizeExcludingSignals(int nFunctions, int nProperties, int nSignals, int nBindings) + static int calculateSizeExcludingSignals(int nFunctions, int nProperties, int nAliases, int nSignals, int nBindings, int nNamedObjectsInComponent) { return ( sizeof(Object) + nFunctions * sizeof(quint32) + nProperties * sizeof(Property) + + nAliases * sizeof(Alias) + nSignals * sizeof(quint32) + nBindings * sizeof(Binding) + + nNamedObjectsInComponent * sizeof(int) + 0x7 ) & ~0x7; } - const quint32 *functionOffsetTable() const + const LEUInt32 *functionOffsetTable() const { - return reinterpret_cast<const quint32*>(reinterpret_cast<const char *>(this) + offsetToFunctions); + return reinterpret_cast<const LEUInt32*>(reinterpret_cast<const char *>(this) + offsetToFunctions); } const Property *propertyTable() const @@ -415,6 +535,11 @@ struct Object return reinterpret_cast<const Property*>(reinterpret_cast<const char *>(this) + offsetToProperties); } + const Alias *aliasTable() const + { + return reinterpret_cast<const Alias*>(reinterpret_cast<const char *>(this) + offsetToAliases); + } + const Binding *bindingTable() const { return reinterpret_cast<const Binding*>(reinterpret_cast<const char *>(this) + offsetToBindings); @@ -422,78 +547,116 @@ struct Object const Signal *signalAt(int idx) const { - const uint *offsetTable = reinterpret_cast<const uint*>((reinterpret_cast<const char *>(this)) + offsetToSignals); - const uint offset = offsetTable[idx]; + const LEUInt32 *offsetTable = reinterpret_cast<const LEUInt32*>((reinterpret_cast<const char *>(this)) + offsetToSignals); + const LEUInt32 offset = offsetTable[idx]; return reinterpret_cast<const Signal*>(reinterpret_cast<const char*>(this) + offset); } + + const LEUInt32 *namedObjectsInComponentTable() const + { + return reinterpret_cast<const LEUInt32*>(reinterpret_cast<const char *>(this) + offsetToNamedObjectsInComponent); + } + + // --- QQmlPropertyCacheCreator interface + int propertyCount() const { return nProperties; } + int aliasCount() const { return nAliases; } + int signalCount() const { return nSignals; } + int functionCount() const { return nFunctions; } + + const Binding *bindingsBegin() const { return bindingTable(); } + const Binding *bindingsEnd() const { return bindingTable() + nBindings; } + + const Property *propertiesBegin() const { return propertyTable(); } + const Property *propertiesEnd() const { return propertyTable() + nProperties; } + + const Alias *aliasesBegin() const { return aliasTable(); } + const Alias *aliasesEnd() const { return aliasTable() + nAliases; } + + typedef TableIterator<Signal, Object, &Object::signalAt> SignalIterator; + SignalIterator signalsBegin() const { return SignalIterator(this, 0); } + SignalIterator signalsEnd() const { return SignalIterator(this, nSignals); } + + int namedObjectsInComponentCount() const { return nNamedObjectsInComponent; } + // --- }; struct Import { - enum ImportType { + enum ImportType : unsigned int { ImportLibrary = 0x1, ImportFile = 0x2, ImportScript = 0x3 }; - quint32 type; + LEUInt32 type; - quint32 uriIndex; - quint32 qualifierIndex; + LEUInt32 uriIndex; + LEUInt32 qualifierIndex; - qint32 majorVersion; - qint32 minorVersion; + LEInt32 majorVersion; + LEInt32 minorVersion; Location location; - Import(): type(0), uriIndex(0), qualifierIndex(0), majorVersion(0), minorVersion(0) {} + Import() { type = 0; uriIndex = 0; qualifierIndex = 0; majorVersion = 0; minorVersion = 0; } }; static const char magic_str[] = "qv4cdata"; struct Unit { + // DO NOT CHANGE THESE FIELDS EVER char magic[8]; - qint16 architecture; - qint16 version; - quint32 unitSize; // Size of the Unit and any depending data. + LEUInt32 version; + LEUInt32 qtVersion; + LEInt64 sourceTimeStamp; + LEUInt32 unitSize; // Size of the Unit and any depending data. + // END DO NOT CHANGE THESE FIELDS EVER - enum { + char md5Checksum[16]; // checksum of all bytes following this field. + void generateChecksum(); + + LEUInt32 architectureIndex; // string index to QSysInfo::buildAbi() + LEUInt32 codeGeneratorIndex; + char dependencyMD5Checksum[16]; + + enum : unsigned int { IsJavascript = 0x1, IsQml = 0x2, StaticData = 0x4, // Unit data persistent in memory? IsSingleton = 0x8, - IsSharedLibrary = 0x10 // .pragma shared? + IsSharedLibrary = 0x10, // .pragma shared? + ContainsMachineCode = 0x20 // used to determine if we need to mmap with execute permissions }; - quint32 flags; - uint stringTableSize; - uint offsetToStringTable; - uint functionTableSize; - uint offsetToFunctionTable; - uint lookupTableSize; - uint offsetToLookupTable; - uint regexpTableSize; - uint offsetToRegexpTable; - uint constantTableSize; - uint offsetToConstantTable; - uint jsClassTableSize; - uint offsetToJSClassTable; - qint32 indexOfRootFunction; - quint32 sourceFileIndex; + LEUInt32 flags; + LEUInt32 stringTableSize; + LEUInt32 offsetToStringTable; + LEUInt32 functionTableSize; + LEUInt32 offsetToFunctionTable; + LEUInt32 lookupTableSize; + LEUInt32 offsetToLookupTable; + LEUInt32 regexpTableSize; + LEUInt32 offsetToRegexpTable; + LEUInt32 constantTableSize; + LEUInt32 offsetToConstantTable; + LEUInt32 jsClassTableSize; + LEUInt32 offsetToJSClassTable; + LEInt32 indexOfRootFunction; + LEUInt32 sourceFileIndex; /* QML specific fields */ - quint32 nImports; - quint32 offsetToImports; - quint32 nObjects; - quint32 offsetToObjects; - quint32 indexOfRootObject; + LEUInt32 nImports; + LEUInt32 offsetToImports; + LEUInt32 nObjects; + LEUInt32 offsetToObjects; + LEUInt32 indexOfRootObject; const Import *importAt(int idx) const { return reinterpret_cast<const Import*>((reinterpret_cast<const char *>(this)) + offsetToImports + idx * sizeof(Import)); } const Object *objectAt(int idx) const { - const uint *offsetTable = reinterpret_cast<const uint*>((reinterpret_cast<const char *>(this)) + offsetToObjects); - const uint offset = offsetTable[idx]; + const LEUInt32 *offsetTable = reinterpret_cast<const LEUInt32*>((reinterpret_cast<const char *>(this)) + offsetToObjects); + const LEUInt32 offset = offsetTable[idx]; return reinterpret_cast<const Object*>(reinterpret_cast<const char*>(this) + offset); } @@ -503,22 +666,33 @@ struct Unit /* end QML specific fields*/ QString stringAt(int idx) const { - const uint *offsetTable = reinterpret_cast<const uint*>((reinterpret_cast<const char *>(this)) + offsetToStringTable); - const uint offset = offsetTable[idx]; + const LEUInt32 *offsetTable = reinterpret_cast<const LEUInt32*>((reinterpret_cast<const char *>(this)) + offsetToStringTable); + const LEUInt32 offset = offsetTable[idx]; const String *str = reinterpret_cast<const String*>(reinterpret_cast<const char *>(this) + offset); if (str->size == 0) return QString(); +#if Q_BYTE_ORDER == Q_LITTLE_ENDIAN const QChar *characters = reinterpret_cast<const QChar *>(str + 1); - if (flags & StaticData) - return QString::fromRawData(characters, str->size); + // Too risky to do this while we unmap disk backed compilation but keep pointers to string + // data in the identifier tables. + // if (flags & StaticData) + // return QString::fromRawData(characters, str->size); return QString(characters, str->size); +#else + const LEUInt16 *characters = reinterpret_cast<const LEUInt16 *>(str + 1); + QString qstr(str->size, Qt::Uninitialized); + QChar *ch = qstr.data(); + for (int i = 0; i < str->size; ++i) + ch[i] = QChar(characters[i]); + return qstr; +#endif } - const uint *functionOffsetTable() const { return reinterpret_cast<const uint*>((reinterpret_cast<const char *>(this)) + offsetToFunctionTable); } + const LEUInt32 *functionOffsetTable() const { return reinterpret_cast<const LEUInt32*>((reinterpret_cast<const char *>(this)) + offsetToFunctionTable); } const Function *functionAt(int idx) const { - const uint *offsetTable = functionOffsetTable(); - const uint offset = offsetTable[idx]; + const LEUInt32 *offsetTable = functionOffsetTable(); + const LEUInt32 offset = offsetTable[idx]; return reinterpret_cast<const Function*>(reinterpret_cast<const char *>(this) + offset); } @@ -526,27 +700,18 @@ struct Unit const RegExp *regexpAt(int index) const { return reinterpret_cast<const RegExp*>(reinterpret_cast<const char *>(this) + offsetToRegexpTable + index * sizeof(RegExp)); } - const QV4::Value *constants() const { - return reinterpret_cast<const QV4::Value*>(reinterpret_cast<const char *>(this) + offsetToConstantTable); + const LEUInt64 *constants() const { + return reinterpret_cast<const LEUInt64*>(reinterpret_cast<const char *>(this) + offsetToConstantTable); } const JSClassMember *jsClassAt(int idx, int *nMembers) const { - const uint *offsetTable = reinterpret_cast<const uint *>(reinterpret_cast<const char *>(this) + offsetToJSClassTable); - const uint offset = offsetTable[idx]; + const LEUInt32 *offsetTable = reinterpret_cast<const LEUInt32 *>(reinterpret_cast<const char *>(this) + offsetToJSClassTable); + const LEUInt32 offset = offsetTable[idx]; const char *ptr = reinterpret_cast<const char *>(this) + offset; const JSClass *klass = reinterpret_cast<const JSClass *>(ptr); *nMembers = klass->nMembers; return reinterpret_cast<const JSClassMember*>(ptr + sizeof(JSClass)); } - - static int calculateSize(uint nFunctions, uint nRegExps, uint nConstants, - uint nLookups, uint nClasses) { - return (sizeof(Unit) - + (nFunctions + nClasses) * sizeof(uint) - + nRegExps * RegExp::calculateSize() - + nConstants * sizeof(QV4::ReturnedValue) - + nLookups * Lookup::calculateSize() - + 7) & ~7; } }; #if defined(Q_CC_MSVC) || defined(Q_CC_GNU) @@ -565,7 +730,7 @@ struct TypeReference bool errorWhenNotFound: 1; }; -// map from name index to location of first use +// Map from name index to location of first use. struct TypeReferenceMap : QHash<int, TypeReference> { TypeReference &add(int nameIndex, const Location &loc) { @@ -574,7 +739,75 @@ struct TypeReferenceMap : QHash<int, TypeReference> return *it; return *insert(nameIndex, loc); } + + template <typename CompiledObject> + void collectFromObject(const CompiledObject *obj) + { + if (obj->inheritedTypeNameIndex != 0) { + TypeReference &r = this->add(obj->inheritedTypeNameIndex, obj->location); + r.needsCreation = true; + r.errorWhenNotFound = true; + } + + for (auto prop = obj->propertiesBegin(), propEnd = obj->propertiesEnd(); prop != propEnd; ++prop) { + if (prop->type >= QV4::CompiledData::Property::Custom) { + // ### FIXME: We could report the more accurate location here by using prop->location, but the old + // compiler can't and the tests expect it to be the object location right now. + TypeReference &r = this->add(prop->customTypeNameIndex, obj->location); + r.errorWhenNotFound = true; + } + } + + for (auto binding = obj->bindingsBegin(), bindingEnd = obj->bindingsEnd(); binding != bindingEnd; ++binding) { + if (binding->type == QV4::CompiledData::Binding::Type_AttachedProperty) + this->add(binding->propertyNameIndex, binding->location); + } + } + + template <typename Iterator> + void collectFromObjects(Iterator it, Iterator end) + { + for (; it != end; ++it) + collectFromObject(*it); + } +}; + +#ifndef V4_BOOTSTRAP +struct ResolvedTypeReference +{ + ResolvedTypeReference() + : type(0) + , majorVersion(0) + , minorVersion(0) + , isFullyDynamicType(false) + {} + + QQmlType *type; + QQmlRefPointer<QQmlPropertyCache> typePropertyCache; + QQmlRefPointer<QV4::CompiledData::CompilationUnit> compilationUnit; + + int majorVersion; + int minorVersion; + // Types such as QQmlPropertyMap can add properties dynamically at run-time and + // therefore cannot have a property cache installed when instantiated. + bool isFullyDynamicType; + + QQmlPropertyCache *propertyCache() const; + QQmlPropertyCache *createPropertyCache(QQmlEngine *); + bool addToHash(QCryptographicHash *hash, QQmlEngine *engine); + + void doDynamicTypeCheck(); }; +// map from name index +// While this could be a hash, a map is chosen here to provide a stable +// order, which is used to calculating a check-sum on dependent meta-objects. +struct ResolvedTypeReferenceMap: public QMap<int, ResolvedTypeReference*> +{ + bool addToHash(QCryptographicHash *hash, QQmlEngine *engine) const; +}; +#else +struct ResolvedTypeReferenceMap {}; +#endif // index is per-object binding index typedef QVector<QQmlPropertyData*> BindingPropertyData; @@ -597,7 +830,7 @@ struct Q_QML_PRIVATE_EXPORT CompilationUnit : public QQmlRefCount virtual ~CompilationUnit(); #endif - Unit *data; + const Unit *data; // Called only when building QML, when we build the header for JS first and append QML data virtual QV4::CompiledData::Unit *createUnitData(QmlIR::Document *irDocument); @@ -614,20 +847,81 @@ struct Q_QML_PRIVATE_EXPORT CompilationUnit : public QQmlRefCount QVector<QV4::Function *> runtimeFunctions; mutable QQmlNullableValue<QUrl> m_url; + // QML specific fields + QQmlPropertyCacheVector propertyCaches; + QQmlPropertyCache *rootPropertyCache() const { return propertyCaches.at(data->indexOfRootObject); } + + QQmlRefPointer<QQmlTypeNameCache> importCache; + // index is object index. This allows fast access to the // property data when initializing bindings, avoiding expensive // lookups by string (property name). QVector<BindingPropertyData> bindingPropertyDataPerObject; + // mapping from component object index (CompiledData::Unit object index that points to component) to identifier hash of named objects + // this is initialized on-demand by QQmlContextData + QHash<int, IdentifierHash<int>> namedObjectsPerComponentCache; + IdentifierHash<int> namedObjectsPerComponent(int componentObjectIndex); + + // pointers either to data->constants() or little-endian memory copy. + const Value* constants; + + void finalize(QQmlEnginePrivate *engine); + + int totalBindingsCount; // Number of bindings used in this type + int totalParserStatusCount; // Number of instantiated types that are QQmlParserStatus subclasses + int totalObjectCount; // Number of objects explicitly instantiated + + QVector<QQmlScriptData *> dependentScripts; + ResolvedTypeReferenceMap resolvedTypes; + + bool verifyChecksum(QQmlEngine *engine, + const ResolvedTypeReferenceMap &dependentTypes) const; + + int metaTypeId; + int listMetaTypeId; + bool isRegisteredWithEngine; + + QScopedPointer<CompilationUnitMapper> backingFile; + + // --- interface for QQmlPropertyCacheCreator + typedef Object CompiledObject; + int objectCount() const { return data->nObjects; } + int rootObjectIndex() const { return data->indexOfRootObject; } + const Object *objectAt(int index) const { return data->objectAt(index); } + QString stringAt(int index) const { return data->stringAt(index); } + + struct FunctionIterator + { + FunctionIterator(const Unit *unit, const Object *object, int index) : unit(unit), object(object), index(index) {} + const Unit *unit; + const Object *object; + int index; + + const Function *operator->() const { return unit->functionAt(object->functionOffsetTable()[index]); } + void operator++() { ++index; } + bool operator==(const FunctionIterator &rhs) const { return index == rhs.index; } + bool operator!=(const FunctionIterator &rhs) const { return index != rhs.index; } + }; + FunctionIterator objectFunctionsBegin(const Object *object) const { return FunctionIterator(data, object, 0); } + FunctionIterator objectFunctionsEnd(const Object *object) const { return FunctionIterator(data, object, object->nFunctions); } + // --- + QV4::Function *linkToEngine(QV4::ExecutionEngine *engine); void unlink(); - virtual QV4::ExecutableAllocator::ChunkOfPages *chunkForFunction(int /*functionIndex*/) { return 0; } - void markObjects(QV4::ExecutionEngine *e); + void destroy() Q_DECL_OVERRIDE; + + bool saveToDisk(const QUrl &unitUrl, QString *errorString); + bool loadFromDisk(const QUrl &url, EvalISelFactory *iselFactory, QString *errorString); + protected: virtual void linkBackendToEngine(QV4::ExecutionEngine *engine) = 0; + virtual void prepareCodeOffsetsForDiskStorage(CompiledData::Unit *unit); + virtual bool saveCodeToDisk(QIODevice *device, const CompiledData::Unit *unit, QString *errorString); + virtual bool memoryMapCode(QString *errorString); #endif // V4_BOOTSTRAP }; |