Fix endian support in compiled data structures

The goal is to make the compiled data structures persistent on disk. In order
to make it possible to create these data structures on a "host" system that may
have a different endianness than the target system, we now make all the word
sized fields little-endian. The template wrappers from QJson provide
zero-overhead access for little-endian machines (the vast majority) while
maintaining a large degree of source compatibility.

Change-Id: I3d30da1fcf3bffb98dbe9337d3a35482fb7b57c8
Reviewed-by: Lars Knoll <lars.knoll@qt.io>
This commit is contained in:
Simon Hausmann 2016-07-12 14:19:09 +02:00
parent 8dc7cb73ff
commit be491913c0
12 changed files with 221 additions and 167 deletions

View File

@ -193,7 +193,7 @@ void Object::appendFunction(QmlIR::Function *f)
QString Object::appendBinding(Binding *b, bool isListBinding) QString Object::appendBinding(Binding *b, bool isListBinding)
{ {
const bool bindingToDefaultProperty = (b->propertyNameIndex == 0); const bool bindingToDefaultProperty = (b->propertyNameIndex == quint32(0));
if (!isListBinding && !bindingToDefaultProperty if (!isListBinding && !bindingToDefaultProperty
&& b->type != QV4::CompiledData::Binding::Type_GroupProperty && b->type != QV4::CompiledData::Binding::Type_GroupProperty
&& b->type != QV4::CompiledData::Binding::Type_AttachedProperty && b->type != QV4::CompiledData::Binding::Type_AttachedProperty
@ -640,7 +640,10 @@ bool IRBuilder::visit(QQmlJS::AST::UiImport *node)
} }
if (node->versionToken.isValid()) { if (node->versionToken.isValid()) {
extractVersion(textRefAt(node->versionToken), &import->majorVersion, &import->minorVersion); int major, minor;
extractVersion(textRefAt(node->versionToken), &major, &minor);
import->majorVersion = major;
import->minorVersion = minor;
} else if (import->type == QV4::CompiledData::Import::ImportLibrary) { } else if (import->type == QV4::CompiledData::Import::ImportLibrary) {
recordError(node->importIdToken, QCoreApplication::translate("QQmlParser","Library import requires a version")); recordError(node->importIdToken, QCoreApplication::translate("QQmlParser","Library import requires a version"));
return false; return false;
@ -997,13 +1000,13 @@ void IRBuilder::setBindingValue(QV4::CompiledData::Binding *binding, QQmlJS::AST
binding->value.b = false; binding->value.b = false;
} else if (QQmlJS::AST::NumericLiteral *lit = QQmlJS::AST::cast<QQmlJS::AST::NumericLiteral *>(expr)) { } else if (QQmlJS::AST::NumericLiteral *lit = QQmlJS::AST::cast<QQmlJS::AST::NumericLiteral *>(expr)) {
binding->type = QV4::CompiledData::Binding::Type_Number; binding->type = QV4::CompiledData::Binding::Type_Number;
binding->value.d = lit->value; binding->setNumberValueInternal(lit->value);
} else { } else {
if (QQmlJS::AST::UnaryMinusExpression *unaryMinus = QQmlJS::AST::cast<QQmlJS::AST::UnaryMinusExpression *>(expr)) { if (QQmlJS::AST::UnaryMinusExpression *unaryMinus = QQmlJS::AST::cast<QQmlJS::AST::UnaryMinusExpression *>(expr)) {
if (QQmlJS::AST::NumericLiteral *lit = QQmlJS::AST::cast<QQmlJS::AST::NumericLiteral *>(unaryMinus->expression)) { if (QQmlJS::AST::NumericLiteral *lit = QQmlJS::AST::cast<QQmlJS::AST::NumericLiteral *>(unaryMinus->expression)) {
binding->type = QV4::CompiledData::Binding::Type_Number; binding->type = QV4::CompiledData::Binding::Type_Number;
binding->value.d = -lit->value; binding->setNumberValueInternal(-lit->value);
} }
} }
} }

View File

@ -350,7 +350,7 @@ public:
int id; int id;
int indexOfDefaultPropertyOrAlias; int indexOfDefaultPropertyOrAlias;
bool defaultPropertyIsAlias; bool defaultPropertyIsAlias;
int flags; quint32 flags;
QV4::CompiledData::Location location; QV4::CompiledData::Location location;
QV4::CompiledData::Location locationOfIdProperty; QV4::CompiledData::Location locationOfIdProperty;

View File

@ -546,7 +546,7 @@ bool QQmlEnumTypeResolver::assignEnumToBinding(QmlIR::Binding *binding, const QS
COMPILE_EXCEPTION(binding, tr("Invalid property assignment: Enum value \"%1\" cannot start with a lowercase letter").arg(enumName.toString())); COMPILE_EXCEPTION(binding, tr("Invalid property assignment: Enum value \"%1\" cannot start with a lowercase letter").arg(enumName.toString()));
} }
binding->type = QV4::CompiledData::Binding::Type_Number; binding->type = QV4::CompiledData::Binding::Type_Number;
binding->value.d = (double)enumValue; binding->setNumberValueInternal((double)enumValue);
binding->flags |= QV4::CompiledData::Binding::IsResolvedEnum; binding->flags |= QV4::CompiledData::Binding::IsResolvedEnum;
return true; return true;
} }
@ -701,7 +701,7 @@ void QQmlAliasAnnotator::annotateBindingsToAliases()
if (!binding->isValueBinding()) if (!binding->isValueBinding())
continue; continue;
bool notInRevision = false; bool notInRevision = false;
QQmlPropertyData *pd = binding->propertyNameIndex != 0 ? resolver.property(stringAt(binding->propertyNameIndex), &notInRevision) : defaultProperty; QQmlPropertyData *pd = binding->propertyNameIndex != quint32(0) ? resolver.property(stringAt(binding->propertyNameIndex), &notInRevision) : defaultProperty;
if (pd && pd->isAlias()) if (pd && pd->isAlias())
binding->flags |= QV4::CompiledData::Binding::IsBindingToAlias; binding->flags |= QV4::CompiledData::Binding::IsBindingToAlias;
} }
@ -733,7 +733,7 @@ void QQmlScriptStringScanner::scan()
if (binding->type != QV4::CompiledData::Binding::Type_Script) if (binding->type != QV4::CompiledData::Binding::Type_Script)
continue; continue;
bool notInRevision = false; bool notInRevision = false;
QQmlPropertyData *pd = binding->propertyNameIndex != 0 ? resolver.property(stringAt(binding->propertyNameIndex), &notInRevision) : defaultProperty; QQmlPropertyData *pd = binding->propertyNameIndex != quint32(0) ? resolver.property(stringAt(binding->propertyNameIndex), &notInRevision) : defaultProperty;
if (!pd || pd->propType != scriptStringMetaType) if (!pd || pd->propType != scriptStringMetaType)
continue; continue;
@ -783,7 +783,7 @@ void QQmlComponentAndAliasResolver::findAndRegisterImplicitComponents(const QmlI
} }
QQmlPropertyData *pd = 0; QQmlPropertyData *pd = 0;
if (binding->propertyNameIndex != 0) { if (binding->propertyNameIndex != quint32(0)) {
bool notInRevision = false; bool notInRevision = false;
pd = propertyResolver.property(stringAt(binding->propertyNameIndex), &notInRevision); pd = propertyResolver.property(stringAt(binding->propertyNameIndex), &notInRevision);
} else { } else {
@ -1346,7 +1346,7 @@ void QQmlDefaultPropertyMerger::mergeDefaultProperties(int objectIndex)
QmlIR::Binding *previousBinding = 0; QmlIR::Binding *previousBinding = 0;
QmlIR::Binding *binding = object->firstBinding(); QmlIR::Binding *binding = object->firstBinding();
while (binding) { while (binding) {
if (binding->propertyNameIndex == 0 || stringAt(binding->propertyNameIndex) != defaultProperty) { if (binding->propertyNameIndex == quint32(0) || stringAt(binding->propertyNameIndex) != defaultProperty) {
previousBinding = binding; previousBinding = binding;
binding = binding->next; binding = binding->next;
continue; continue;

View File

@ -122,7 +122,7 @@ QV4::Function *CompilationUnit::linkToEngine(ExecutionEngine *engine)
for (uint i = 0; i < data->lookupTableSize; ++i) { for (uint i = 0; i < data->lookupTableSize; ++i) {
QV4::Lookup *l = runtimeLookups + i; QV4::Lookup *l = runtimeLookups + i;
Lookup::Type type = Lookup::Type(compiledLookups[i].type_and_flags); Lookup::Type type = Lookup::Type(uint(compiledLookups[i].type_and_flags));
if (type == CompiledData::Lookup::Type_Getter) if (type == CompiledData::Lookup::Type_Getter)
l->getter = QV4::Lookup::getterGeneric; l->getter = QV4::Lookup::getterGeneric;
else if (type == CompiledData::Lookup::Type_Setter) else if (type == CompiledData::Lookup::Type_Setter)
@ -229,7 +229,7 @@ IdentifierHash<int> CompilationUnit::namedObjectsPerComponent(int componentObjec
if (it == namedObjectsPerComponentCache.end()) { if (it == namedObjectsPerComponentCache.end()) {
IdentifierHash<int> namedObjectCache(engine); IdentifierHash<int> namedObjectCache(engine);
const CompiledData::Object *component = data->objectAt(componentObjectIndex); const CompiledData::Object *component = data->objectAt(componentObjectIndex);
const quint32 *namedObjectIndexPtr = component->namedObjectsInComponentTable(); const LEUInt32 *namedObjectIndexPtr = component->namedObjectsInComponentTable();
for (quint32 i = 0; i < component->nNamedObjectsInComponent; ++i, ++namedObjectIndexPtr) { for (quint32 i = 0; i < component->nNamedObjectsInComponent; ++i, ++namedObjectIndexPtr) {
const CompiledData::Object *namedObject = data->objectAt(*namedObjectIndexPtr); const CompiledData::Object *namedObject = data->objectAt(*namedObjectIndexPtr);
namedObjectCache.add(runtimeStrings[namedObject->idNameIndex], namedObject->id); namedObjectCache.add(runtimeStrings[namedObject->idNameIndex], namedObject->id);
@ -355,7 +355,7 @@ QString Binding::valueAsString(const Unit *unit) const
case Type_Boolean: case Type_Boolean:
return value.b ? QStringLiteral("true") : QStringLiteral("false"); return value.b ? QStringLiteral("true") : QStringLiteral("false");
case Type_Number: case Type_Number:
return QString::number(value.d); return QString::number(valueAsNumber());
case Type_Invalid: case Type_Invalid:
return QString(); return QString();
#ifdef QT_NO_TRANSLATION #ifdef QT_NO_TRANSLATION

View File

@ -62,6 +62,7 @@
#include <private/qqmlnullablevalue_p.h> #include <private/qqmlnullablevalue_p.h>
#include <private/qv4identifier_p.h> #include <private/qv4identifier_p.h>
#include <private/qflagpointer_p.h> #include <private/qflagpointer_p.h>
#include <private/qjson_p.h>
#ifndef V4_BOOTSTRAP #ifndef V4_BOOTSTRAP
#include <private/qqmltypenamecache_p.h> #include <private/qqmltypenamecache_p.h>
#include <private/qqmlpropertycache_p.h> #include <private/qqmlpropertycache_p.h>
@ -90,6 +91,12 @@ struct Function;
namespace CompiledData { 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;
struct String; struct String;
struct Function; struct Function;
struct Lookup; struct Lookup;
@ -115,10 +122,12 @@ struct TableIterator
struct Location struct Location
{ {
quint32 line : 20; union {
quint32 column : 12; QJsonPrivate::qle_bitfield<0, 20> line;
QJsonPrivate::qle_bitfield<20, 12> column;
};
Location(): line(0), column(0) {} Location() { line = 0; column = 0; }
inline bool operator<(const Location &other) const { inline bool operator<(const Location &other) const {
return line < other.line || return line < other.line ||
@ -128,20 +137,22 @@ struct Location
struct RegExp struct RegExp
{ {
enum Flags { enum Flags : unsigned int {
RegExp_Global = 0x01, RegExp_Global = 0x01,
RegExp_IgnoreCase = 0x02, RegExp_IgnoreCase = 0x02,
RegExp_Multiline = 0x04 RegExp_Multiline = 0x04
}; };
quint32 flags : 4; union {
quint32 stringIndex : 28; QJsonPrivate::qle_bitfield<0, 4> flags;
QJsonPrivate::qle_bitfield<4, 28> stringIndex;
};
static int calculateSize() { return sizeof(RegExp); } static int calculateSize() { return sizeof(RegExp); }
}; };
struct Lookup struct Lookup
{ {
enum Type { enum Type : unsigned int {
Type_Getter = 0x0, Type_Getter = 0x0,
Type_Setter = 0x1, Type_Setter = 0x1,
Type_GlobalGetter = 2, Type_GlobalGetter = 2,
@ -149,21 +160,29 @@ struct Lookup
Type_IndexedSetter = 4 Type_IndexedSetter = 4
}; };
quint32 type_and_flags : 4; union {
quint32 nameIndex : 28; QJsonPrivate::qle_bitfield<0, 4> type_and_flags;
QJsonPrivate::qle_bitfield<4, 28> nameIndex;
};
Lookup() { type_and_flags = 0; nameIndex = 0; }
static int calculateSize() { return sizeof(Lookup); } static int calculateSize() { return sizeof(Lookup); }
}; };
struct JSClassMember struct JSClassMember
{ {
quint32 nameOffset : 31; union {
quint32 isAccessor : 1; QJsonPrivate::qle_bitfield<0, 31> nameOffset;
QJsonPrivate::qle_bitfield<31, 1> isAccessor;
};
JSClassMember() { nameOffset = 0; isAccessor = 0; }
}; };
struct JSClass struct JSClass
{ {
uint nMembers; LEUInt32 nMembers;
// JSClassMember[nMembers] // JSClassMember[nMembers]
static int calculateSize(int nMembers) { return (sizeof(JSClass) + nMembers * sizeof(JSClassMember) + 7) & ~7; } static int calculateSize(int nMembers) { return (sizeof(JSClass) + nMembers * sizeof(JSClassMember) + 7) & ~7; }
@ -171,7 +190,7 @@ struct JSClass
struct String struct String
{ {
qint32 size; LEInt32 size;
// uint16 strdata[] // uint16 strdata[]
static int calculateSize(const QString &str) { static int calculateSize(const QString &str) {
@ -181,7 +200,7 @@ struct String
struct Function struct Function
{ {
enum Flags { enum Flags : unsigned int {
HasDirectEval = 0x1, HasDirectEval = 0x1,
UsesArgumentsObject = 0x2, UsesArgumentsObject = 0x2,
IsStrict = 0x4, IsStrict = 0x4,
@ -190,43 +209,43 @@ struct Function
}; };
quint8 flags; quint8 flags;
quint32 nameIndex; LEUInt32 nameIndex;
quint32 nFormals; LEUInt32 nFormals;
quint32 formalsOffset; LEUInt32 formalsOffset;
quint32 nLocals; LEUInt32 nLocals;
quint32 localsOffset; LEUInt32 localsOffset;
quint32 nInnerFunctions; LEUInt32 nInnerFunctions;
quint32 innerFunctionsOffset; LEUInt32 innerFunctionsOffset;
Location location; Location location;
// Qml Extensions Begin // Qml Extensions Begin
quint32 nDependingIdObjects; LEUInt32 nDependingIdObjects;
quint32 dependingIdObjectsOffset; // Array of resolved ID objects LEUInt32 dependingIdObjectsOffset; // Array of resolved ID objects
quint32 nDependingContextProperties; LEUInt32 nDependingContextProperties;
quint32 dependingContextPropertiesOffset; // Array of int pairs (property index and notify index) LEUInt32 dependingContextPropertiesOffset; // Array of int pairs (property index and notify index)
quint32 nDependingScopeProperties; LEUInt32 nDependingScopeProperties;
quint32 dependingScopePropertiesOffset; // Array of int pairs (property index and notify index) LEUInt32 dependingScopePropertiesOffset; // Array of int pairs (property index and notify index)
// Qml Extensions End // Qml Extensions End
// Absolute offset into file where the code for this function is located. Only used when the function // Absolute offset into file where the code for this function is located. Only used when the function
// is serialized. // is serialized.
quint64 codeOffset; LEUInt64 codeOffset;
quint64 codeSize; LEUInt64 codeSize;
// quint32 formalsIndex[nFormals] // quint32 formalsIndex[nFormals]
// quint32 localsIndex[nLocals] // quint32 localsIndex[nLocals]
// quint32 offsetForInnerFunctions[nInnerFunctions] // quint32 offsetForInnerFunctions[nInnerFunctions]
// Function[nInnerFunctions] // Function[nInnerFunctions]
const quint32 *formalsTable() const { return reinterpret_cast<const quint32 *>(reinterpret_cast<const char *>(this) + formalsOffset); } const LEUInt32 *formalsTable() const { return reinterpret_cast<const LEUInt32 *>(reinterpret_cast<const char *>(this) + formalsOffset); }
const quint32 *localsTable() const { return reinterpret_cast<const quint32 *>(reinterpret_cast<const char *>(this) + localsOffset); } const LEUInt32 *localsTable() const { return reinterpret_cast<const LEUInt32 *>(reinterpret_cast<const char *>(this) + localsOffset); }
const quint32 *qmlIdObjectDependencyTable() const { return reinterpret_cast<const quint32 *>(reinterpret_cast<const char *>(this) + dependingIdObjectsOffset); } const LEUInt32 *qmlIdObjectDependencyTable() const { return reinterpret_cast<const LEUInt32 *>(reinterpret_cast<const char *>(this) + dependingIdObjectsOffset); }
const quint32 *qmlContextPropertiesDependencyTable() const { return reinterpret_cast<const quint32 *>(reinterpret_cast<const char *>(this) + dependingContextPropertiesOffset); } const LEUInt32 *qmlContextPropertiesDependencyTable() const { return reinterpret_cast<const LEUInt32 *>(reinterpret_cast<const char *>(this) + dependingContextPropertiesOffset); }
const quint32 *qmlScopePropertiesDependencyTable() const { return reinterpret_cast<const quint32 *>(reinterpret_cast<const char *>(this) + dependingScopePropertiesOffset); } const LEUInt32 *qmlScopePropertiesDependencyTable() const { return reinterpret_cast<const LEUInt32 *>(reinterpret_cast<const char *>(this) + dependingScopePropertiesOffset); }
// --- QQmlPropertyCacheCreator interface // --- QQmlPropertyCacheCreator interface
const quint32 *formalsBegin() const { return formalsTable(); } const LEUInt32 *formalsBegin() const { return formalsTable(); }
const quint32 *formalsEnd() const { return formalsTable() + nFormals; } const LEUInt32 *formalsEnd() const { return formalsTable() + nFormals; }
// --- // ---
inline bool hasQmlDependencies() const { return nDependingIdObjects > 0 || nDependingContextProperties > 0 || nDependingScopeProperties > 0; } inline bool hasQmlDependencies() const { return nDependingIdObjects > 0 || nDependingContextProperties > 0 || nDependingScopeProperties > 0; }
@ -239,15 +258,15 @@ struct Function
// Qml data structures // Qml data structures
struct Q_QML_EXPORT TranslationData { struct Q_QML_EXPORT TranslationData {
quint32 commentIndex; LEUInt32 commentIndex;
int number; LEInt32 number;
}; };
struct Q_QML_PRIVATE_EXPORT Binding struct Q_QML_PRIVATE_EXPORT Binding
{ {
quint32 propertyNameIndex; LEUInt32 propertyNameIndex;
enum ValueType { enum ValueType : unsigned int {
Type_Invalid, Type_Invalid,
Type_Boolean, Type_Boolean,
Type_Number, Type_Number,
@ -260,7 +279,7 @@ struct Q_QML_PRIVATE_EXPORT Binding
Type_GroupProperty Type_GroupProperty
}; };
enum Flags { enum Flags : unsigned int {
IsSignalHandlerExpression = 0x1, IsSignalHandlerExpression = 0x1,
IsSignalHandlerObject = 0x2, IsSignalHandlerObject = 0x2,
IsOnAssignment = 0x4, IsOnAssignment = 0x4,
@ -272,16 +291,18 @@ struct Q_QML_PRIVATE_EXPORT Binding
IsCustomParserBinding = 0x100, IsCustomParserBinding = 0x100,
}; };
quint32 flags : 16; union {
quint32 type : 16; QJsonPrivate::qle_bitfield<0, 16> flags;
QJsonPrivate::qle_bitfield<16, 16> type;
};
union { union {
bool b; bool b;
double d; quint64 doubleValue; // do not access directly, needs endian protected access
quint32 compiledScriptIndex; // used when Type_Script LEUInt32 compiledScriptIndex; // used when Type_Script
quint32 objectIndex; LEUInt32 objectIndex;
TranslationData translationData; // used when Type_Translation TranslationData translationData; // used when Type_Translation
} value; } 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 location;
Location valueLocation; Location valueLocation;
@ -341,11 +362,20 @@ struct Q_QML_PRIVATE_EXPORT Binding
QString valueAsScriptString(const Unit *unit) const; QString valueAsScriptString(const Unit *unit) const;
double valueAsNumber() const double valueAsNumber() const
{ {
if (type == Type_Number) if (type != Type_Number)
return value.d; return 0.0;
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 bool valueAsBoolean() const
{ {
if (type == Type_Boolean) if (type == Type_Boolean)
@ -357,16 +387,16 @@ struct Q_QML_PRIVATE_EXPORT Binding
struct Parameter struct Parameter
{ {
quint32 nameIndex; LEUInt32 nameIndex;
quint32 type; LEUInt32 type;
quint32 customTypeNameIndex; LEUInt32 customTypeNameIndex;
Location location; Location location;
}; };
struct Signal struct Signal
{ {
quint32 nameIndex; LEUInt32 nameIndex;
quint32 nParameters; LEUInt32 nParameters;
Location location; Location location;
// Parameter parameters[1]; // Parameter parameters[1];
@ -389,37 +419,41 @@ struct Signal
struct Property 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, Font, Time, Date, DateTime, Rect, Point, Size,
Vector2D, Vector3D, Vector4D, Matrix4x4, Quaternion, Vector2D, Vector3D, Vector4D, Matrix4x4, Quaternion,
Custom, CustomList }; Custom, CustomList };
enum Flags { enum Flags : unsigned int {
IsReadOnly = 0x1 IsReadOnly = 0x1
}; };
quint32 nameIndex; LEUInt32 nameIndex;
quint32 type : 31; union {
quint32 flags : 1; // readonly QJsonPrivate::qle_bitfield<0, 31> type;
quint32 customTypeNameIndex; // If type >= Custom QJsonPrivate::qle_bitfield<31, 1> flags; // readonly
};
LEUInt32 customTypeNameIndex; // If type >= Custom
Location location; Location location;
}; };
struct Alias { struct Alias {
enum Flags { enum Flags : unsigned int {
IsReadOnly = 0x1, IsReadOnly = 0x1,
Resolved = 0x2, Resolved = 0x2,
AliasPointsToPointerObject = 0x4 AliasPointsToPointerObject = 0x4
}; };
quint32 nameIndex : 29;
quint32 flags : 3;
union { union {
quint32 idIndex; // string index QJsonPrivate::qle_bitfield<0, 29> nameIndex;
quint32 targetObjectId; // object id index (in QQmlContextData::idValues) QJsonPrivate::qle_bitfield<29, 3> flags;
}; };
union { union {
quint32 propertyNameIndex; // string index LEUInt32 idIndex; // string index
qint32 encodedMetaPropertyIndex; LEUInt32 targetObjectId; // object id index (in QQmlContextData::idValues)
};
union {
LEUInt32 propertyNameIndex; // string index
LEInt32 encodedMetaPropertyIndex;
}; };
Location location; Location location;
Location referenceLocation; Location referenceLocation;
@ -432,7 +466,7 @@ struct Alias {
struct Object struct Object
{ {
enum Flags { enum Flags : unsigned int {
NoFlag = 0x0, NoFlag = 0x0,
IsComponent = 0x1, // object was identified to be an explicit or implicit component boundary IsComponent = 0x1, // object was identified to be an explicit or implicit component boundary
HasDeferredBindings = 0x2, // any of the bindings are deferred HasDeferredBindings = 0x2, // any of the bindings are deferred
@ -442,24 +476,26 @@ struct Object
// Depending on the use, this may be the type name to instantiate before instantiating this // 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 // object. For grouped properties the type name will be empty and for attached properties
// it will be the name of the attached type. // it will be the name of the attached type.
quint32 inheritedTypeNameIndex; LEUInt32 inheritedTypeNameIndex;
quint32 idNameIndex; LEUInt32 idNameIndex;
qint32 id : 16; union {
qint32 flags : 15; QJsonPrivate::qle_bitfield<0, 15> flags;
quint32 defaultPropertyIsAlias : 1; QJsonPrivate::qle_bitfield<15, 1> defaultPropertyIsAlias;
qint32 indexOfDefaultPropertyOrAlias; // -1 means no default property declared in this object QJsonPrivate::qle_signedbitfield<16, 16> id;
quint32 nFunctions; };
quint32 offsetToFunctions; LEInt32 indexOfDefaultPropertyOrAlias; // -1 means no default property declared in this object
quint32 nProperties; LEUInt32 nFunctions;
quint32 offsetToProperties; LEUInt32 offsetToFunctions;
quint32 nAliases; LEUInt32 nProperties;
quint32 offsetToAliases; LEUInt32 offsetToProperties;
quint32 nSignals; LEUInt32 nAliases;
quint32 offsetToSignals; // which in turn will be a table with offsets to variable-sized Signal objects LEUInt32 offsetToAliases;
quint32 nBindings; LEUInt32 nSignals;
quint32 offsetToBindings; LEUInt32 offsetToSignals; // which in turn will be a table with offsets to variable-sized Signal objects
quint32 nNamedObjectsInComponent; LEUInt32 nBindings;
quint32 offsetToNamedObjectsInComponent; LEUInt32 offsetToBindings;
LEUInt32 nNamedObjectsInComponent;
LEUInt32 offsetToNamedObjectsInComponent;
Location location; Location location;
Location locationOfIdProperty; Location locationOfIdProperty;
// Function[] // Function[]
@ -480,9 +516,9 @@ struct Object
) & ~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 const Property *propertyTable() const
@ -502,14 +538,14 @@ struct Object
const Signal *signalAt(int idx) const const Signal *signalAt(int idx) const
{ {
const uint *offsetTable = reinterpret_cast<const uint*>((reinterpret_cast<const char *>(this)) + offsetToSignals); const LEUInt32 *offsetTable = reinterpret_cast<const LEUInt32*>((reinterpret_cast<const char *>(this)) + offsetToSignals);
const uint offset = offsetTable[idx]; const LEUInt32 offset = offsetTable[idx];
return reinterpret_cast<const Signal*>(reinterpret_cast<const char*>(this) + offset); return reinterpret_cast<const Signal*>(reinterpret_cast<const char*>(this) + offset);
} }
const quint32 *namedObjectsInComponentTable() const const LEUInt32 *namedObjectsInComponentTable() const
{ {
return reinterpret_cast<const quint32*>(reinterpret_cast<const char *>(this) + offsetToNamedObjectsInComponent); return reinterpret_cast<const LEUInt32*>(reinterpret_cast<const char *>(this) + offsetToNamedObjectsInComponent);
} }
// --- QQmlPropertyCacheCreator interface // --- QQmlPropertyCacheCreator interface
@ -535,22 +571,22 @@ struct Object
struct Import struct Import
{ {
enum ImportType { enum ImportType : unsigned int {
ImportLibrary = 0x1, ImportLibrary = 0x1,
ImportFile = 0x2, ImportFile = 0x2,
ImportScript = 0x3 ImportScript = 0x3
}; };
quint32 type; quint8 type;
quint32 uriIndex; LEUInt32 uriIndex;
quint32 qualifierIndex; LEUInt32 qualifierIndex;
qint32 majorVersion; LEInt32 majorVersion;
qint32 minorVersion; LEInt32 minorVersion;
Location location; 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"; static const char magic_str[] = "qv4cdata";
@ -558,47 +594,47 @@ static const char magic_str[] = "qv4cdata";
struct Unit struct Unit
{ {
char magic[8]; char magic[8];
qint16 architecture; LEInt16 architecture;
qint16 version; LEInt16 version;
quint32 unitSize; // Size of the Unit and any depending data. LEUInt32 unitSize; // Size of the Unit and any depending data.
enum { enum : unsigned int {
IsJavascript = 0x1, IsJavascript = 0x1,
IsQml = 0x2, IsQml = 0x2,
StaticData = 0x4, // Unit data persistent in memory? StaticData = 0x4, // Unit data persistent in memory?
IsSingleton = 0x8, IsSingleton = 0x8,
IsSharedLibrary = 0x10 // .pragma shared? IsSharedLibrary = 0x10 // .pragma shared?
}; };
quint32 flags; LEUInt32 flags;
uint stringTableSize; LEUInt32 stringTableSize;
uint offsetToStringTable; LEUInt32 offsetToStringTable;
uint functionTableSize; LEUInt32 functionTableSize;
uint offsetToFunctionTable; LEUInt32 offsetToFunctionTable;
uint lookupTableSize; LEUInt32 lookupTableSize;
uint offsetToLookupTable; LEUInt32 offsetToLookupTable;
uint regexpTableSize; LEUInt32 regexpTableSize;
uint offsetToRegexpTable; LEUInt32 offsetToRegexpTable;
uint constantTableSize; LEUInt32 constantTableSize;
uint offsetToConstantTable; LEUInt32 offsetToConstantTable;
uint jsClassTableSize; LEUInt32 jsClassTableSize;
uint offsetToJSClassTable; LEUInt32 offsetToJSClassTable;
qint32 indexOfRootFunction; LEInt32 indexOfRootFunction;
quint32 sourceFileIndex; LEUInt32 sourceFileIndex;
/* QML specific fields */ /* QML specific fields */
quint32 nImports; LEUInt32 nImports;
quint32 offsetToImports; LEUInt32 offsetToImports;
quint32 nObjects; LEUInt32 nObjects;
quint32 offsetToObjects; LEUInt32 offsetToObjects;
quint32 indexOfRootObject; LEUInt32 indexOfRootObject;
const Import *importAt(int idx) const { const Import *importAt(int idx) const {
return reinterpret_cast<const Import*>((reinterpret_cast<const char *>(this)) + offsetToImports + idx * sizeof(Import)); return reinterpret_cast<const Import*>((reinterpret_cast<const char *>(this)) + offsetToImports + idx * sizeof(Import));
} }
const Object *objectAt(int idx) const { const Object *objectAt(int idx) const {
const uint *offsetTable = reinterpret_cast<const uint*>((reinterpret_cast<const char *>(this)) + offsetToObjects); const LEUInt32 *offsetTable = reinterpret_cast<const LEUInt32*>((reinterpret_cast<const char *>(this)) + offsetToObjects);
const uint offset = offsetTable[idx]; const LEUInt32 offset = offsetTable[idx];
return reinterpret_cast<const Object*>(reinterpret_cast<const char*>(this) + offset); return reinterpret_cast<const Object*>(reinterpret_cast<const char*>(this) + offset);
} }
@ -608,22 +644,31 @@ struct Unit
/* end QML specific fields*/ /* end QML specific fields*/
QString stringAt(int idx) const { QString stringAt(int idx) const {
const uint *offsetTable = reinterpret_cast<const uint*>((reinterpret_cast<const char *>(this)) + offsetToStringTable); const LEUInt32 *offsetTable = reinterpret_cast<const LEUInt32*>((reinterpret_cast<const char *>(this)) + offsetToStringTable);
const uint offset = offsetTable[idx]; const LEUInt32 offset = offsetTable[idx];
const String *str = reinterpret_cast<const String*>(reinterpret_cast<const char *>(this) + offset); const String *str = reinterpret_cast<const String*>(reinterpret_cast<const char *>(this) + offset);
if (str->size == 0) if (str->size == 0)
return QString(); return QString();
#if Q_BYTE_ORDER == Q_LITTLE_ENDIAN
const QChar *characters = reinterpret_cast<const QChar *>(str + 1); const QChar *characters = reinterpret_cast<const QChar *>(str + 1);
if (flags & StaticData) if (flags & StaticData)
return QString::fromRawData(characters, str->size); return QString::fromRawData(characters, str->size);
return QString(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 Function *functionAt(int idx) const {
const uint *offsetTable = functionOffsetTable(); const LEUInt32 *offsetTable = functionOffsetTable();
const uint offset = offsetTable[idx]; const LEUInt32 offset = offsetTable[idx];
return reinterpret_cast<const Function*>(reinterpret_cast<const char *>(this) + offset); return reinterpret_cast<const Function*>(reinterpret_cast<const char *>(this) + offset);
} }
@ -636,8 +681,8 @@ struct Unit
} }
const JSClassMember *jsClassAt(int idx, int *nMembers) const { const JSClassMember *jsClassAt(int idx, int *nMembers) const {
const uint *offsetTable = reinterpret_cast<const uint *>(reinterpret_cast<const char *>(this) + offsetToJSClassTable); const LEUInt32 *offsetTable = reinterpret_cast<const LEUInt32 *>(reinterpret_cast<const char *>(this) + offsetToJSClassTable);
const uint offset = offsetTable[idx]; const LEUInt32 offset = offsetTable[idx];
const char *ptr = reinterpret_cast<const char *>(this) + offset; const char *ptr = reinterpret_cast<const char *>(this) + offset;
const JSClass *klass = reinterpret_cast<const JSClass *>(ptr); const JSClass *klass = reinterpret_cast<const JSClass *>(ptr);
*nMembers = klass->nMembers; *nMembers = klass->nMembers;

View File

@ -83,7 +83,13 @@ void QV4::Compiler::StringTableGenerator::serialize(CompiledData::Unit *unit)
QV4::CompiledData::String *s = (QV4::CompiledData::String*)(stringData); QV4::CompiledData::String *s = (QV4::CompiledData::String*)(stringData);
s->size = qstr.length(); s->size = qstr.length();
#if Q_BYTE_ORDER == Q_LITTLE_ENDIAN
memcpy(s + 1, qstr.constData(), qstr.length()*sizeof(ushort)); memcpy(s + 1, qstr.constData(), qstr.length()*sizeof(ushort));
#else
ushort *uc = reinterpret_cast<ushort *>(s + 1);
for (int i = 0; i < qstr.length(); ++i)
uc[i] = qToLittleEndian<ushort>(qstr.at(i).unicode());
#endif
stringData += QV4::CompiledData::String::calculateSize(qstr); stringData += QV4::CompiledData::String::calculateSize(qstr);
} }

View File

@ -59,7 +59,7 @@ Function::Function(ExecutionEngine *engine, CompiledData::CompilationUnit *unit,
Q_UNUSED(engine); Q_UNUSED(engine);
internalClass = engine->emptyClass; internalClass = engine->emptyClass;
const quint32 *formalsIndices = compiledFunction->formalsTable(); const CompiledData::LEUInt32 *formalsIndices = compiledFunction->formalsTable();
// iterate backwards, so we get the right ordering for duplicate names // iterate backwards, so we get the right ordering for duplicate names
Scope scope(engine); Scope scope(engine);
ScopedString arg(scope); ScopedString arg(scope);
@ -78,7 +78,7 @@ Function::Function(ExecutionEngine *engine, CompiledData::CompilationUnit *unit,
} }
nFormals = compiledFunction->nFormals; nFormals = compiledFunction->nFormals;
const quint32 *localsIndices = compiledFunction->localsTable(); const CompiledData::LEUInt32 *localsIndices = compiledFunction->localsTable();
for (quint32 i = 0; i < compiledFunction->nLocals; ++i) for (quint32 i = 0; i < compiledFunction->nLocals; ++i)
internalClass = internalClass->addMember(compilationUnit->runtimeStrings[localsIndices[i]]->identifier, Attr_NotConfigurable); internalClass = internalClass->addMember(compilationUnit->runtimeStrings[localsIndices[i]]->identifier, Attr_NotConfigurable);
@ -110,7 +110,7 @@ void Function::updateInternalClass(ExecutionEngine *engine, const QList<QByteArr
} }
nFormals = parameters.size(); nFormals = parameters.size();
const quint32 *localsIndices = compiledFunction->localsTable(); const CompiledData::LEUInt32 *localsIndices = compiledFunction->localsTable();
for (quint32 i = 0; i < compiledFunction->nLocals; ++i) for (quint32 i = 0; i < compiledFunction->nLocals; ++i)
internalClass = internalClass->addMember(compilationUnit->runtimeStrings[localsIndices[i]]->identifier, Attr_NotConfigurable); internalClass = internalClass->addMember(compilationUnit->runtimeStrings[localsIndices[i]]->identifier, Attr_NotConfigurable);

View File

@ -312,7 +312,7 @@ void QQmlPropertyCapture::registerQmlDependencies(const QV4::CompiledData::Funct
QV4::Scoped<QV4::QmlContext> context(scope, engine->qmlContext()); QV4::Scoped<QV4::QmlContext> context(scope, engine->qmlContext());
QQmlContextData *qmlContext = context->qmlContext(); QQmlContextData *qmlContext = context->qmlContext();
const quint32 *idObjectDependency = compiledFunction->qmlIdObjectDependencyTable(); const QV4::CompiledData::LEUInt32 *idObjectDependency = compiledFunction->qmlIdObjectDependencyTable();
const int idObjectDependencyCount = compiledFunction->nDependingIdObjects; const int idObjectDependencyCount = compiledFunction->nDependingIdObjects;
for (int i = 0; i < idObjectDependencyCount; ++i, ++idObjectDependency) { for (int i = 0; i < idObjectDependencyCount; ++i, ++idObjectDependency) {
Q_ASSERT(int(*idObjectDependency) < qmlContext->idValueCount); Q_ASSERT(int(*idObjectDependency) < qmlContext->idValueCount);
@ -321,7 +321,7 @@ void QQmlPropertyCapture::registerQmlDependencies(const QV4::CompiledData::Funct
} }
Q_ASSERT(qmlContext->contextObject); Q_ASSERT(qmlContext->contextObject);
const quint32 *contextPropertyDependency = compiledFunction->qmlContextPropertiesDependencyTable(); const QV4::CompiledData::LEUInt32 *contextPropertyDependency = compiledFunction->qmlContextPropertiesDependencyTable();
const int contextPropertyDependencyCount = compiledFunction->nDependingContextProperties; const int contextPropertyDependencyCount = compiledFunction->nDependingContextProperties;
for (int i = 0; i < contextPropertyDependencyCount; ++i) { for (int i = 0; i < contextPropertyDependencyCount; ++i) {
const int propertyIndex = *contextPropertyDependency++; const int propertyIndex = *contextPropertyDependency++;
@ -331,7 +331,7 @@ void QQmlPropertyCapture::registerQmlDependencies(const QV4::CompiledData::Funct
} }
QObject *scopeObject = context->qmlScope(); QObject *scopeObject = context->qmlScope();
const quint32 *scopePropertyDependency = compiledFunction->qmlScopePropertiesDependencyTable(); const QV4::CompiledData::LEUInt32 *scopePropertyDependency = compiledFunction->qmlScopePropertiesDependencyTable();
const int scopePropertyDependencyCount = compiledFunction->nDependingScopeProperties; const int scopePropertyDependencyCount = compiledFunction->nDependingScopeProperties;
for (int i = 0; i < scopePropertyDependencyCount; ++i) { for (int i = 0; i < scopePropertyDependencyCount; ++i) {
const int propertyIndex = *scopePropertyDependency++; const int propertyIndex = *scopePropertyDependency++;

View File

@ -999,7 +999,7 @@ void QQmlObjectCreator::setupFunctions()
QV4::ScopedValue function(scope); QV4::ScopedValue function(scope);
QV4::ScopedContext qmlContext(scope, currentQmlContext()); QV4::ScopedContext qmlContext(scope, currentQmlContext());
const quint32 *functionIdx = _compiledObject->functionOffsetTable(); const QV4::CompiledData::LEUInt32 *functionIdx = _compiledObject->functionOffsetTable();
for (quint32 i = 0; i < _compiledObject->nFunctions; ++i, ++functionIdx) { for (quint32 i = 0; i < _compiledObject->nFunctions; ++i, ++functionIdx) {
QV4::Function *runtimeFunction = compilationUnit->runtimeFunctions[*functionIdx]; QV4::Function *runtimeFunction = compilationUnit->runtimeFunctions[*functionIdx];
const QString name = runtimeFunction->name()->toQString(); const QString name = runtimeFunction->name()->toQString();

View File

@ -630,7 +630,7 @@ int QQmlVMEMetaObject::metaCall(QObject *o, QMetaObject::Call c, int _id, void *
id -= propOffset(); id -= propOffset();
if (id < propertyCount) { if (id < propertyCount) {
const QV4::CompiledData::Property::Type t = static_cast<QV4::CompiledData::Property::Type>(compiledObject->propertyTable()[id].type); const QV4::CompiledData::Property::Type t = static_cast<QV4::CompiledData::Property::Type>(qint32(compiledObject->propertyTable()[id].type));
bool needActivate = false; bool needActivate = false;
if (t == QV4::CompiledData::Property::Var) { if (t == QV4::CompiledData::Property::Var) {

View File

@ -133,14 +133,14 @@ void tst_qmldiskcache::regenerateAfterChange()
const QV4::CompiledData::Unit *testUnit = testCompiler.mapUnit(); const QV4::CompiledData::Unit *testUnit = testCompiler.mapUnit();
QVERIFY2(testUnit, qPrintable(testCompiler.lastErrorString)); QVERIFY2(testUnit, qPrintable(testCompiler.lastErrorString));
QCOMPARE(testUnit->nObjects, quint32(1)); QCOMPARE(quint32(testUnit->nObjects), quint32(1));
const QV4::CompiledData::Object *obj = testUnit->objectAt(0); const QV4::CompiledData::Object *obj = testUnit->objectAt(0);
QCOMPARE(obj->nBindings, quint32(1)); QCOMPARE(quint32(obj->nBindings), quint32(1));
QCOMPARE(obj->bindingTable()->type, quint32(QV4::CompiledData::Binding::Type_Script)); QCOMPARE(quint32(obj->bindingTable()->type), quint32(QV4::CompiledData::Binding::Type_Script));
QCOMPARE(obj->bindingTable()->value.compiledScriptIndex, quint32(1)); QCOMPARE(quint32(obj->bindingTable()->value.compiledScriptIndex), quint32(1));
QCOMPARE(testUnit->functionTableSize, quint32(2)); QCOMPARE(quint32(testUnit->functionTableSize), quint32(2));
const QV4::CompiledData::Function *bindingFunction = testUnit->functionAt(1); const QV4::CompiledData::Function *bindingFunction = testUnit->functionAt(1);
QVERIFY(bindingFunction->codeOffset > testUnit->unitSize); QVERIFY(bindingFunction->codeOffset > testUnit->unitSize);
@ -163,14 +163,14 @@ void tst_qmldiskcache::regenerateAfterChange()
const QV4::CompiledData::Unit *testUnit = testCompiler.mapUnit(); const QV4::CompiledData::Unit *testUnit = testCompiler.mapUnit();
QVERIFY2(testUnit, qPrintable(testCompiler.lastErrorString)); QVERIFY2(testUnit, qPrintable(testCompiler.lastErrorString));
QCOMPARE(testUnit->nObjects, quint32(1)); QCOMPARE(quint32(testUnit->nObjects), quint32(1));
const QV4::CompiledData::Object *obj = testUnit->objectAt(0); const QV4::CompiledData::Object *obj = testUnit->objectAt(0);
QCOMPARE(obj->nBindings, quint32(2)); QCOMPARE(quint32(obj->nBindings), quint32(2));
QCOMPARE(obj->bindingTable()->type, quint32(QV4::CompiledData::Binding::Type_Number)); QCOMPARE(quint32(obj->bindingTable()->type), quint32(QV4::CompiledData::Binding::Type_Number));
QCOMPARE(obj->bindingTable()->value.d, double(42)); QCOMPARE(obj->bindingTable()->valueAsNumber(), double(42));
QCOMPARE(testUnit->functionTableSize, quint32(2)); QCOMPARE(quint32(testUnit->functionTableSize), quint32(2));
const QV4::CompiledData::Function *bindingFunction = testUnit->functionAt(1); const QV4::CompiledData::Function *bindingFunction = testUnit->functionAt(1);
QVERIFY(bindingFunction->codeOffset > testUnit->unitSize); QVERIFY(bindingFunction->codeOffset > testUnit->unitSize);

View File

@ -95,7 +95,7 @@ void tst_qqmltranslation::translation()
if (expectCompiledTranslation) { if (expectCompiledTranslation) {
if (binding->type != QV4::CompiledData::Binding::Type_Translation) if (binding->type != QV4::CompiledData::Binding::Type_Translation)
qDebug() << "binding for property" << propertyName << "is not a compiled translation"; qDebug() << "binding for property" << propertyName << "is not a compiled translation";
QCOMPARE(binding->type, quint32(QV4::CompiledData::Binding::Type_Translation)); QCOMPARE(quint32(binding->type), quint32(QV4::CompiledData::Binding::Type_Translation));
} else { } else {
if (binding->type == QV4::CompiledData::Binding::Type_Translation) if (binding->type == QV4::CompiledData::Binding::Type_Translation)
qDebug() << "binding for property" << propertyName << "is not supposed to be a compiled translation"; qDebug() << "binding for property" << propertyName << "is not supposed to be a compiled translation";
@ -147,7 +147,7 @@ void tst_qqmltranslation::idTranslation()
if (propertyName == "idTranslation") { if (propertyName == "idTranslation") {
if (binding->type != QV4::CompiledData::Binding::Type_TranslationById) if (binding->type != QV4::CompiledData::Binding::Type_TranslationById)
qDebug() << "binding for property" << propertyName << "is not a compiled translation"; qDebug() << "binding for property" << propertyName << "is not a compiled translation";
QCOMPARE(binding->type, quint32(QV4::CompiledData::Binding::Type_TranslationById)); QCOMPARE(quint32(binding->type), quint32(QV4::CompiledData::Binding::Type_TranslationById));
} else { } else {
QVERIFY(binding->type != QV4::CompiledData::Binding::Type_Translation); QVERIFY(binding->type != QV4::CompiledData::Binding::Type_Translation);
} }