qtdeclarative/src/qml/compiler/qv4compileddata_p.h

927 lines
30 KiB
C++

/****************************************************************************
**
** Copyright (C) 2016 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of the QtQml module of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:LGPL$
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and The Qt Company. For licensing terms
** and conditions see https://www.qt.io/terms-conditions. For further
** information use the contact form at https://www.qt.io/contact-us.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 3 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL3 included in the
** packaging of this file. Please review the following information to
** ensure the GNU Lesser General Public License version 3 requirements
** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 2.0 or (at your option) the GNU General
** Public license version 3 or any later version approved by the KDE Free
** Qt Foundation. The licenses are as published by the Free Software
** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
** included in the packaging of this file. Please review the following
** information to ensure the GNU General Public License requirements will
** be met: https://www.gnu.org/licenses/gpl-2.0.html and
** https://www.gnu.org/licenses/gpl-3.0.html.
**
** $QT_END_LICENSE$
**
****************************************************************************/
#ifndef QV4COMPILEDDATA_P_H
#define QV4COMPILEDDATA_P_H
//
// W A R N I N G
// -------------
//
// This file is not part of the Qt API. It exists purely as an
// implementation detail. This header file may change from version to
// version without notice, or even be removed.
//
// We mean it.
//
#include <QtCore/qstring.h>
#include <QVector>
#include <QStringList>
#include <QHash>
#include <QUrl>
#include <private/qv4value_p.h>
#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 0x01
class QIODevice;
class QQmlPropertyCache;
class QQmlPropertyData;
class QQmlTypeNameCache;
class QQmlScriptData;
class QQmlType;
class QQmlEngine;
namespace QmlIR {
struct Document;
}
namespace QV4 {
namespace IR {
struct Function;
}
struct Function;
class EvalISelFactory;
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
{
union {
QJsonPrivate::qle_bitfield<0, 20> line;
QJsonPrivate::qle_bitfield<20, 12> column;
};
Location() { line = 0; column = 0; }
inline bool operator<(const Location &other) const {
return line < other.line ||
(line == other.line && column < other.column);
}
};
struct RegExp
{
enum Flags : unsigned int {
RegExp_Global = 0x01,
RegExp_IgnoreCase = 0x02,
RegExp_Multiline = 0x04
};
union {
QJsonPrivate::qle_bitfield<0, 4> flags;
QJsonPrivate::qle_bitfield<4, 28> stringIndex;
};
RegExp() { flags = 0; stringIndex = 0; }
};
struct Lookup
{
enum Type : unsigned int {
Type_Getter = 0x0,
Type_Setter = 0x1,
Type_GlobalGetter = 2,
Type_IndexedGetter = 3,
Type_IndexedSetter = 4
};
union {
QJsonPrivate::qle_bitfield<0, 4> type_and_flags;
QJsonPrivate::qle_bitfield<4, 28> nameIndex;
};
Lookup() { type_and_flags = 0; nameIndex = 0; }
};
struct JSClassMember
{
union {
QJsonPrivate::qle_bitfield<0, 31> nameOffset;
QJsonPrivate::qle_bitfield<31, 1> isAccessor;
};
JSClassMember() { nameOffset = 0; isAccessor = 0; }
};
struct JSClass
{
LEUInt32 nMembers;
// JSClassMember[nMembers]
static int calculateSize(int nMembers) { return (sizeof(JSClass) + nMembers * sizeof(JSClassMember) + 7) & ~7; }
};
struct String
{
LEInt32 size;
// uint16 strdata[]
static int calculateSize(const QString &str) {
return (sizeof(String) + str.length() * sizeof(quint16) + 7) & ~0x7;
}
};
struct Function
{
enum Flags : unsigned int {
HasDirectEval = 0x1,
UsesArgumentsObject = 0x2,
IsStrict = 0x4,
IsNamedExpression = 0x8,
HasCatchOrWith = 0x10
};
LEUInt32 nameIndex;
LEUInt32 nFormals;
LEUInt32 formalsOffset;
LEUInt32 nLocals;
LEUInt32 localsOffset;
LEUInt32 nInnerFunctions;
Location location;
// Qml Extensions Begin
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
// Absolute offset into file where the code for this function is located. Only used when the function
// is serialized.
LEUInt64 codeOffset;
LEUInt64 codeSize;
// quint32 formalsIndex[nFormals]
// quint32 localsIndex[nLocals]
// quint32 offsetForInnerFunctions[nInnerFunctions]
// Function[nInnerFunctions]
// 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; }
static int calculateSize(int nFormals, int nLocals, int nInnerfunctions, int nIdObjectDependencies, int nPropertyDependencies) {
return (sizeof(Function) + (nFormals + nLocals + nInnerfunctions + nIdObjectDependencies + 2 * nPropertyDependencies) * sizeof(quint32) + 7) & ~0x7;
}
};
// Qml data structures
struct Q_QML_EXPORT TranslationData {
LEUInt32 commentIndex;
LEInt32 number;
};
struct Q_QML_PRIVATE_EXPORT Binding
{
LEUInt32 propertyNameIndex;
enum ValueType : unsigned int {
Type_Invalid,
Type_Boolean,
Type_Number,
Type_String,
Type_Translation,
Type_TranslationById,
Type_Script,
Type_Object,
Type_AttachedProperty,
Type_GroupProperty
};
enum Flags : unsigned int {
IsSignalHandlerExpression = 0x1,
IsSignalHandlerObject = 0x2,
IsOnAssignment = 0x4,
InitializerForReadOnlyDeclaration = 0x8,
IsResolvedEnum = 0x10,
IsListItem = 0x20,
IsBindingToAlias = 0x40,
IsDeferredBinding = 0x80,
IsCustomParserBinding = 0x100,
};
union {
QJsonPrivate::qle_bitfield<0, 16> flags;
QJsonPrivate::qle_bitfield<16, 16> type;
};
union {
bool b;
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;
LEUInt32 stringIndex; // Set for Type_String, Type_Translation and Type_Script (the latter because of script strings)
Location location;
Location valueLocation;
bool isValueBinding() const
{
if (type == Type_AttachedProperty
|| type == Type_GroupProperty)
return false;
if (flags & IsSignalHandlerExpression
|| flags & IsSignalHandlerObject)
return false;
return true;
}
bool isValueBindingNoAlias() const { return isValueBinding() && !(flags & IsBindingToAlias); }
bool isValueBindingToAlias() const { return isValueBinding() && (flags & IsBindingToAlias); }
bool isSignalHandler() const
{
if (flags & IsSignalHandlerExpression || flags & IsSignalHandlerObject) {
Q_ASSERT(!isValueBinding());
Q_ASSERT(!isAttachedProperty());
Q_ASSERT(!isGroupProperty());
return true;
}
return false;
}
bool isAttachedProperty() const
{
if (type == Type_AttachedProperty) {
Q_ASSERT(!isValueBinding());
Q_ASSERT(!isSignalHandler());
Q_ASSERT(!isGroupProperty());
return true;
}
return false;
}
bool isGroupProperty() const
{
if (type == Type_GroupProperty) {
Q_ASSERT(!isValueBinding());
Q_ASSERT(!isSignalHandler());
Q_ASSERT(!isAttachedProperty());
return true;
}
return false;
}
static QString escapedString(const QString &string);
bool evaluatesToString() const { return type == Type_String || type == Type_Translation || type == Type_TranslationById; }
QString valueAsString(const Unit *unit) const;
QString valueAsScriptString(const Unit *unit) const;
double valueAsNumber() const
{
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)
return value.b;
return false;
}
};
struct Parameter
{
LEUInt32 nameIndex;
LEUInt32 type;
LEUInt32 customTypeNameIndex;
Location location;
};
struct Signal
{
LEUInt32 nameIndex;
LEUInt32 nParameters;
Location location;
// Parameter parameters[1];
const Parameter *parameterAt(int idx) const {
return reinterpret_cast<const Parameter*>(this + 1) + idx;
}
static int calculateSize(int nParameters) {
return (sizeof(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 : unsigned int { Var = 0, Variant, Int, Bool, Real, String, Url, Color,
Font, Time, Date, DateTime, Rect, Point, Size,
Vector2D, Vector3D, Vector4D, Matrix4x4, Quaternion,
Custom, CustomList };
enum Flags : unsigned int {
IsReadOnly = 0x1
};
LEUInt32 nameIndex;
union {
QJsonPrivate::qle_bitfield<0, 31> type;
QJsonPrivate::qle_bitfield<31, 1> flags; // readonly
};
LEUInt32 customTypeNameIndex; // If type >= Custom
Location location;
};
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.
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[]
// Property[]
// Signal[]
// Binding[]
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 LEUInt32 *functionOffsetTable() const
{
return reinterpret_cast<const LEUInt32*>(reinterpret_cast<const char *>(this) + offsetToFunctions);
}
const Property *propertyTable() const
{
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);
}
const Signal *signalAt(int idx) const
{
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 : unsigned int {
ImportLibrary = 0x1,
ImportFile = 0x2,
ImportScript = 0x3
};
quint8 type;
LEUInt32 uriIndex;
LEUInt32 qualifierIndex;
LEInt32 majorVersion;
LEInt32 minorVersion;
Location location;
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];
LEUInt32 version;
LEUInt32 qtVersion;
LEInt64 sourceTimeStamp;
LEUInt32 unitSize; // Size of the Unit and any depending data.
// END DO NOT CHANGE THESE FIELDS EVER
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?
};
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 */
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 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);
}
bool isSingleton() const {
return flags & Unit::IsSingleton;
}
/* end QML specific fields*/
QString stringAt(int idx) const {
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);
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 LEUInt32 *functionOffsetTable() const { return reinterpret_cast<const LEUInt32*>((reinterpret_cast<const char *>(this)) + offsetToFunctionTable); }
const Function *functionAt(int idx) const {
const LEUInt32 *offsetTable = functionOffsetTable();
const LEUInt32 offset = offsetTable[idx];
return reinterpret_cast<const Function*>(reinterpret_cast<const char *>(this) + offset);
}
const Lookup *lookupTable() const { return reinterpret_cast<const Lookup*>(reinterpret_cast<const char *>(this) + offsetToLookupTable); }
const RegExp *regexpAt(int index) const {
return reinterpret_cast<const RegExp*>(reinterpret_cast<const char *>(this) + offsetToRegexpTable + index * sizeof(RegExp));
}
const LEUInt64 *constants() const {
return reinterpret_cast<const LEUInt64*>(reinterpret_cast<const char *>(this) + offsetToConstantTable);
}
const JSClassMember *jsClassAt(int idx, int *nMembers) const {
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));
}
};
#if defined(Q_CC_MSVC) || defined(Q_CC_GNU)
#pragma pack(pop)
#endif
struct TypeReference
{
TypeReference(const Location &loc)
: location(loc)
, needsCreation(false)
, errorWhenNotFound(false)
{}
Location location; // first use
bool needsCreation : 1; // whether the type needs to be creatable or not
bool errorWhenNotFound: 1;
};
// map from name index to location of first use
struct TypeReferenceMap : QHash<int, TypeReference>
{
TypeReference &add(int nameIndex, const Location &loc) {
Iterator it = find(nameIndex);
if (it != end())
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 *);
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;
// This is how this hooks into the existing structures:
//VM::Function
// CompilationUnit * (for functions that need to clean up)
// CompiledData::Function *compiledFunction
struct Q_QML_PRIVATE_EXPORT CompilationUnit : public QQmlRefCount
{
#ifdef V4_BOOTSTRAP
CompilationUnit()
: data(0)
{}
virtual ~CompilationUnit() {}
#else
CompilationUnit();
virtual ~CompilationUnit();
#endif
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);
#ifndef V4_BOOTSTRAP
ExecutionEngine *engine;
QString fileName() const { return data->stringAt(data->sourceFileIndex); }
QUrl url() const { if (m_url.isNull) m_url = QUrl(fileName()); return m_url; }
QV4::Heap::String **runtimeStrings; // Array
QV4::Lookup *runtimeLookups;
QV4::Value *runtimeRegularExpressions;
QV4::InternalClass **runtimeClasses;
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<QIODevice> 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();
void markObjects(QV4::ExecutionEngine *e);
void destroy() Q_DECL_OVERRIDE;
bool saveToDisk(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
};
}
}
Q_DECLARE_TYPEINFO(QV4::CompiledData::JSClassMember, Q_PRIMITIVE_TYPE);
QT_END_NAMESPACE
#endif