aboutsummaryrefslogtreecommitdiffstats
path: root/src/qml/compiler
diff options
context:
space:
mode:
Diffstat (limited to 'src/qml/compiler')
-rw-r--r--src/qml/compiler/compiler.pri26
-rw-r--r--src/qml/compiler/qqmlirbuilder.cpp582
-rw-r--r--src/qml/compiler/qqmlirbuilder_p.h139
-rw-r--r--src/qml/compiler/qqmlpropertycachecreator.cpp99
-rw-r--r--src/qml/compiler/qqmlpropertycachecreator_p.h841
-rw-r--r--src/qml/compiler/qqmlpropertyvalidator.cpp727
-rw-r--r--src/qml/compiler/qqmlpropertyvalidator_p.h91
-rw-r--r--src/qml/compiler/qqmltypecompiler.cpp1420
-rw-r--r--src/qml/compiler/qqmltypecompiler_p.h348
-rw-r--r--src/qml/compiler/qv4bytecodegenerator.cpp4
-rw-r--r--src/qml/compiler/qv4bytecodegenerator_p.h64
-rw-r--r--src/qml/compiler/qv4bytecodehandler.cpp7
-rw-r--r--src/qml/compiler/qv4bytecodehandler_p.h3
-rw-r--r--src/qml/compiler/qv4codegen.cpp546
-rw-r--r--src/qml/compiler/qv4codegen_p.h301
-rw-r--r--src/qml/compiler/qv4compilationunitmapper.cpp62
-rw-r--r--src/qml/compiler/qv4compilationunitmapper_unix.cpp108
-rw-r--r--src/qml/compiler/qv4compilationunitmapper_win.cpp128
-rw-r--r--src/qml/compiler/qv4compileddata.cpp1030
-rw-r--r--src/qml/compiler/qv4compileddata_p.h1316
-rw-r--r--src/qml/compiler/qv4compiler.cpp79
-rw-r--r--src/qml/compiler/qv4compiler_p.h11
-rw-r--r--src/qml/compiler/qv4compilercontext.cpp26
-rw-r--r--src/qml/compiler/qv4compilercontext_p.h14
-rw-r--r--src/qml/compiler/qv4compilercontrolflow_p.h11
-rw-r--r--src/qml/compiler/qv4compilerglobal_p.h (renamed from src/qml/compiler/qv4compilationunitmapper_p.h)39
-rw-r--r--src/qml/compiler/qv4compilerscanfunctions.cpp62
-rw-r--r--src/qml/compiler/qv4compilerscanfunctions_p.h101
-rw-r--r--src/qml/compiler/qv4instr_moth.cpp107
-rw-r--r--src/qml/compiler/qv4instr_moth_p.h64
-rw-r--r--src/qml/compiler/qv4util_p.h195
31 files changed, 1143 insertions, 7408 deletions
diff --git a/src/qml/compiler/compiler.pri b/src/qml/compiler/compiler.pri
index da3c173545..4d6926d420 100644
--- a/src/qml/compiler/compiler.pri
+++ b/src/qml/compiler/compiler.pri
@@ -3,20 +3,19 @@ INCLUDEPATH += $$OUT_PWD
HEADERS += \
$$PWD/qv4bytecodegenerator_p.h \
- $$PWD/qv4compileddata_p.h \
$$PWD/qv4compiler_p.h \
$$PWD/qv4compilercontext_p.h \
$$PWD/qv4compilercontrolflow_p.h \
+ $$PWD/qv4compilerglobal_p.h \
$$PWD/qv4compilerscanfunctions_p.h \
$$PWD/qv4codegen_p.h \
$$PWD/qqmlirbuilder_p.h \
- $$PWD/qqmltypecompiler_p.h \
$$PWD/qv4instr_moth_p.h \
- $$PWD/qv4bytecodehandler_p.h
+ $$PWD/qv4bytecodehandler_p.h \
+ $$PWD/qv4util_p.h
SOURCES += \
$$PWD/qv4bytecodegenerator.cpp \
- $$PWD/qv4compileddata.cpp \
$$PWD/qv4compiler.cpp \
$$PWD/qv4compilercontext.cpp \
$$PWD/qv4compilerscanfunctions.cpp \
@@ -25,25 +24,6 @@ SOURCES += \
$$PWD/qv4instr_moth.cpp \
$$PWD/qv4bytecodehandler.cpp
-!qmldevtools_build {
-
-HEADERS += \
- $$PWD/qqmltypecompiler_p.h \
- $$PWD/qqmlpropertycachecreator_p.h \
- $$PWD/qqmlpropertyvalidator_p.h \
- $$PWD/qv4compilationunitmapper_p.h
-
-
-SOURCES += \
- $$PWD/qqmltypecompiler.cpp \
- $$PWD/qqmlpropertycachecreator.cpp \
- $$PWD/qqmlpropertyvalidator.cpp \
- $$PWD/qv4compilationunitmapper.cpp
-
-unix: SOURCES += $$PWD/qv4compilationunitmapper_unix.cpp
-else: SOURCES += $$PWD/qv4compilationunitmapper_win.cpp
-}
-
gcc {
equals(QT_GCC_MAJOR_VERSION, 5): QMAKE_CXXFLAGS += -fno-strict-aliasing
}
diff --git a/src/qml/compiler/qqmlirbuilder.cpp b/src/qml/compiler/qqmlirbuilder.cpp
index 9218c4a652..665d2633a7 100644
--- a/src/qml/compiler/qqmlirbuilder.cpp
+++ b/src/qml/compiler/qqmlirbuilder.cpp
@@ -39,7 +39,7 @@
#include "qqmlirbuilder_p.h"
-#include <private/qv4value_p.h>
+#include <private/qv4staticvalue_p.h>
#include <private/qv4compileddata_p.h>
#include <private/qqmljsparser_p.h>
#include <private/qqmljslexer_p.h>
@@ -48,12 +48,6 @@
#include <QCryptographicHash>
#include <cmath>
-#ifndef V4_BOOTSTRAP
-#include <private/qqmlglobal_p.h>
-#include <private/qqmltypeloader_p.h>
-#include <private/qqmlengine_p.h>
-#endif
-
#ifdef CONST
#undef CONST
#endif
@@ -61,12 +55,8 @@
QT_USE_NAMESPACE
static const quint32 emptyStringIndex = 0;
-
-#if 0 //ndef V4_BOOTSTRAP
-DEFINE_BOOL_CONFIG_OPTION(lookupHints, QML_LOOKUP_HINTS);
-#endif // V4_BOOTSTRAP
-
using namespace QmlIR;
+using namespace QQmlJS;
#define COMPILE_EXCEPTION(location, desc) \
{ \
@@ -74,6 +64,84 @@ using namespace QmlIR;
return false; \
}
+bool Parameter::init(QV4::Compiler::JSUnitGenerator *stringGenerator, const QString &parameterName,
+ const QString &typeName)
+{
+ return init(this, stringGenerator, stringGenerator->registerString(parameterName), stringGenerator->registerString(typeName));
+}
+
+bool Parameter::init(QV4::CompiledData::Parameter *param, const QV4::Compiler::JSUnitGenerator *stringGenerator,
+ int parameterNameIndex, int typeNameIndex)
+{
+ param->nameIndex = parameterNameIndex;
+ return initType(&param->type, stringGenerator, typeNameIndex);
+}
+
+bool Parameter::initType(QV4::CompiledData::ParameterType *paramType, const QV4::Compiler::JSUnitGenerator *stringGenerator, int typeNameIndex)
+{
+ paramType->indexIsBuiltinType = false;
+ paramType->typeNameIndexOrBuiltinType = 0;
+ const QString typeName = stringGenerator->stringForIndex(typeNameIndex);
+ auto builtinType = stringToBuiltinType(typeName);
+ if (builtinType == QV4::CompiledData::BuiltinType::InvalidBuiltin) {
+ if (typeName.isEmpty() || !typeName.at(0).isUpper())
+ return false;
+ paramType->indexIsBuiltinType = false;
+ paramType->typeNameIndexOrBuiltinType = typeNameIndex;
+ Q_ASSERT(quint32(typeNameIndex) < (1u << 31));
+ } else {
+ paramType->indexIsBuiltinType = true;
+ paramType->typeNameIndexOrBuiltinType = static_cast<quint32>(builtinType);
+ Q_ASSERT(quint32(builtinType) < (1u << 31));
+ }
+ return true;
+}
+
+QV4::CompiledData::BuiltinType Parameter::stringToBuiltinType(const QString &typeName)
+{
+ static const struct TypeNameToType {
+ const char *name;
+ size_t nameLength;
+ QV4::CompiledData::BuiltinType type;
+ } propTypeNameToTypes[] = {
+ { "int", strlen("int"), QV4::CompiledData::BuiltinType::Int },
+ { "bool", strlen("bool"), QV4::CompiledData::BuiltinType::Bool },
+ { "double", strlen("double"), QV4::CompiledData::BuiltinType::Real },
+ { "real", strlen("real"), QV4::CompiledData::BuiltinType::Real },
+ { "string", strlen("string"), QV4::CompiledData::BuiltinType::String },
+ { "url", strlen("url"), QV4::CompiledData::BuiltinType::Url },
+ { "color", strlen("color"), QV4::CompiledData::BuiltinType::Color },
+ // Internally QTime, QDate and QDateTime are all supported.
+ // To be more consistent with JavaScript we expose only
+ // QDateTime as it matches closely with the Date JS type.
+ // We also call it "date" to match.
+ // { "time", strlen("time"), Property::Time },
+ // { "date", strlen("date"), Property::Date },
+ { "date", strlen("date"), QV4::CompiledData::BuiltinType::DateTime },
+ { "rect", strlen("rect"), QV4::CompiledData::BuiltinType::Rect },
+ { "point", strlen("point"), QV4::CompiledData::BuiltinType::Point },
+ { "size", strlen("size"), QV4::CompiledData::BuiltinType::Size },
+ { "font", strlen("font"), QV4::CompiledData::BuiltinType::Font },
+ { "vector2d", strlen("vector2d"), QV4::CompiledData::BuiltinType::Vector2D },
+ { "vector3d", strlen("vector3d"), QV4::CompiledData::BuiltinType::Vector3D },
+ { "vector4d", strlen("vector4d"), QV4::CompiledData::BuiltinType::Vector4D },
+ { "quaternion", strlen("quaternion"), QV4::CompiledData::BuiltinType::Quaternion },
+ { "matrix4x4", strlen("matrix4x4"), QV4::CompiledData::BuiltinType::Matrix4x4 },
+ { "variant", strlen("variant"), QV4::CompiledData::BuiltinType::Variant },
+ { "var", strlen("var"), QV4::CompiledData::BuiltinType::Var }
+ };
+ static const int propTypeNameToTypesCount = sizeof(propTypeNameToTypes) /
+ sizeof(propTypeNameToTypes[0]);
+
+ for (int typeIndex = 0; typeIndex < propTypeNameToTypesCount; ++typeIndex) {
+ const TypeNameToType *t = propTypeNameToTypes + typeIndex;
+ if (typeName == QLatin1String(t->name, static_cast<int>(t->nameLength))) {
+ return t->type;
+ }
+ }
+ return QV4::CompiledData::BuiltinType::InvalidBuiltin;
+}
+
void Object::init(QQmlJS::MemoryPool *pool, int typeNameIndex, int idIndex, const QQmlJS::AST::SourceLocation &loc)
{
inheritedTypeNameIndex = typeNameIndex;
@@ -258,64 +326,11 @@ QStringList Signal::parameterStringList(const QV4::Compiler::StringTableGenerato
{
QStringList result;
result.reserve(parameters->count);
- for (SignalParameter *param = parameters->first; param; param = param->next)
+ for (Parameter *param = parameters->first; param; param = param->next)
result << stringPool->stringForIndex(param->nameIndex);
return result;
}
-static void replaceWithSpace(QString &str, int idx, int n)
-{
- QChar *data = str.data() + idx;
- const QChar space(QLatin1Char(' '));
- for (int ii = 0; ii < n; ++ii)
- *data++ = space;
-}
-
-void Document::removeScriptPragmas(QString &script)
-{
- const QLatin1String pragma("pragma");
- const QLatin1String library("library");
-
- QQmlJS::Lexer l(nullptr);
- l.setCode(script, 0);
-
- int token = l.lex();
-
- while (true) {
- if (token != QQmlJSGrammar::T_DOT)
- return;
-
- int startOffset = l.tokenOffset();
- int startLine = l.tokenStartLine();
-
- token = l.lex();
-
- if (token != QQmlJSGrammar::T_PRAGMA ||
- l.tokenStartLine() != startLine ||
- script.midRef(l.tokenOffset(), l.tokenLength()) != pragma)
- return;
-
- token = l.lex();
-
- if (token != QQmlJSGrammar::T_IDENTIFIER ||
- l.tokenStartLine() != startLine)
- return;
-
- const QStringRef pragmaValue = script.midRef(l.tokenOffset(), l.tokenLength());
- int endOffset = l.tokenLength() + l.tokenOffset();
-
- token = l.lex();
- if (l.tokenStartLine() == startLine)
- return;
-
- if (pragmaValue == library) {
- replaceWithSpace(script, startOffset, endOffset - startOffset);
- } else {
- return;
- }
- }
-}
-
Document::Document(bool debugMode)
: jsModule(debugMode)
, program(nullptr)
@@ -385,13 +400,12 @@ bool IRBuilder::generateFromQml(const QString &code, const QString &url, Documen
if (!parseResult || !diagnosticMessages.isEmpty()) {
// Extract errors from the parser
for (const QQmlJS::DiagnosticMessage &m : diagnosticMessages) {
-
if (m.isWarning()) {
- qWarning("%s:%d : %s", qPrintable(url), m.loc.startLine, qPrintable(m.message));
+ qWarning("%s:%d : %s", qPrintable(url), m.line, qPrintable(m.message));
continue;
}
- recordError(m.loc, m.message);
+ errors << m;
}
return false;
}
@@ -661,11 +675,9 @@ bool IRBuilder::visit(QQmlJS::AST::UiImport *node)
return false;
}
- if (node->versionToken.isValid()) {
- int major, minor;
- extractVersion(textRefAt(node->versionToken), &major, &minor);
- import->majorVersion = major;
- import->minorVersion = minor;
+ if (node->version) {
+ import->majorVersion = node->version->majorVersion;
+ import->minorVersion = node->version->minorVersion;
} else if (import->type == QV4::CompiledData::Import::ImportLibrary) {
recordError(node->importIdToken, QCoreApplication::translate("QQmlParser","Library import requires a version"));
return false;
@@ -778,40 +790,6 @@ bool IRBuilder::visit(QQmlJS::AST::UiEnumDeclaration *node)
bool IRBuilder::visit(QQmlJS::AST::UiPublicMember *node)
{
- static const struct TypeNameToType {
- const char *name;
- size_t nameLength;
- QV4::CompiledData::Property::Type type;
- } propTypeNameToTypes[] = {
- { "int", strlen("int"), QV4::CompiledData::Property::Int },
- { "bool", strlen("bool"), QV4::CompiledData::Property::Bool },
- { "double", strlen("double"), QV4::CompiledData::Property::Real },
- { "real", strlen("real"), QV4::CompiledData::Property::Real },
- { "string", strlen("string"), QV4::CompiledData::Property::String },
- { "url", strlen("url"), QV4::CompiledData::Property::Url },
- { "color", strlen("color"), QV4::CompiledData::Property::Color },
- // Internally QTime, QDate and QDateTime are all supported.
- // To be more consistent with JavaScript we expose only
- // QDateTime as it matches closely with the Date JS type.
- // We also call it "date" to match.
- // { "time", strlen("time"), Property::Time },
- // { "date", strlen("date"), Property::Date },
- { "date", strlen("date"), QV4::CompiledData::Property::DateTime },
- { "rect", strlen("rect"), QV4::CompiledData::Property::Rect },
- { "point", strlen("point"), QV4::CompiledData::Property::Point },
- { "size", strlen("size"), QV4::CompiledData::Property::Size },
- { "font", strlen("font"), QV4::CompiledData::Property::Font },
- { "vector2d", strlen("vector2d"), QV4::CompiledData::Property::Vector2D },
- { "vector3d", strlen("vector3d"), QV4::CompiledData::Property::Vector3D },
- { "vector4d", strlen("vector4d"), QV4::CompiledData::Property::Vector4D },
- { "quaternion", strlen("quaternion"), QV4::CompiledData::Property::Quaternion },
- { "matrix4x4", strlen("matrix4x4"), QV4::CompiledData::Property::Matrix4x4 },
- { "variant", strlen("variant"), QV4::CompiledData::Property::Variant },
- { "var", strlen("var"), QV4::CompiledData::Property::Var }
- };
- static const int propTypeNameToTypesCount = sizeof(propTypeNameToTypes) /
- sizeof(propTypeNameToTypes[0]);
-
if (node->type == QQmlJS::AST::UiPublicMember::Signal) {
Signal *signal = New<Signal>();
QString signalName = node->name.toString();
@@ -821,7 +799,7 @@ bool IRBuilder::visit(QQmlJS::AST::UiPublicMember *node)
signal->location.line = loc.startLine;
signal->location.column = loc.startColumn;
- signal->parameters = New<PoolList<SignalParameter> >();
+ signal->parameters = New<PoolList<Parameter> >();
QQmlJS::AST::UiParameterList *p = node->parameters;
while (p) {
@@ -832,38 +810,13 @@ bool IRBuilder::visit(QQmlJS::AST::UiPublicMember *node)
return false;
}
- const TypeNameToType *type = nullptr;
- for (int typeIndex = 0; typeIndex < propTypeNameToTypesCount; ++typeIndex) {
- const TypeNameToType *t = propTypeNameToTypes + typeIndex;
- if (memberType == QLatin1String(t->name, static_cast<int>(t->nameLength))) {
- type = t;
- break;
- }
- }
-
- SignalParameter *param = New<SignalParameter>();
-
- if (!type) {
- if (memberType.at(0).isUpper()) {
- // Must be a QML object type.
- // Lazily determine type during compilation.
- param->type = QV4::CompiledData::Property::Custom;
- param->customTypeNameIndex = registerString(memberType);
- } else {
- QString errStr = QCoreApplication::translate("QQmlParser","Invalid signal parameter type: ");
- errStr.append(memberType);
- recordError(node->typeToken, errStr);
- return false;
- }
- } else {
- // the parameter is a known basic type
- param->type = type->type;
- param->customTypeNameIndex = emptyStringIndex;
+ Parameter *param = New<Parameter>();
+ if (!param->init(jsGenerator, p->name.toString(), memberType)) {
+ QString errStr = QCoreApplication::translate("QQmlParser","Invalid signal parameter type: ");
+ errStr.append(memberType);
+ recordError(node->typeToken, errStr);
+ return false;
}
-
- param->nameIndex = registerString(p->name.toString());
- param->location.line = p->identifierToken.startLine;
- param->location.column = p->identifierToken.startColumn;
signal->parameters->append(param);
p = p->next;
}
@@ -886,25 +839,21 @@ bool IRBuilder::visit(QQmlJS::AST::UiPublicMember *node)
} else {
const QStringRef &name = node->name;
- bool typeFound = false;
- QV4::CompiledData::Property::Type type = QV4::CompiledData::Property::Var;
+ Property *property = New<Property>();
+ property->isReadOnly = node->isReadonlyMember;
- for (int ii = 0; !typeFound && ii < propTypeNameToTypesCount; ++ii) {
- const TypeNameToType *t = propTypeNameToTypes + ii;
- if (memberType == QLatin1String(t->name, static_cast<int>(t->nameLength))) {
- type = t->type;
- typeFound = true;
- }
- }
+ QV4::CompiledData::BuiltinType builtinPropertyType = Parameter::stringToBuiltinType(memberType);
+ bool typeFound = builtinPropertyType != QV4::CompiledData::BuiltinType::InvalidBuiltin;
+ if (typeFound)
+ property->setBuiltinType(builtinPropertyType);
if (!typeFound && memberType.at(0).isUpper()) {
const QStringRef &typeModifier = node->typeModifier;
- if (typeModifier.isEmpty()) {
- type = QV4::CompiledData::Property::Custom;
- } else if (typeModifier == QLatin1String("list")) {
- type = QV4::CompiledData::Property::CustomList;
- } else {
+ property->setCustomType(registerString(memberType));
+ if (typeModifier == QLatin1String("list")) {
+ property->isList = true;
+ } else if (!typeModifier.isEmpty()) {
recordError(node->typeModifierToken, QCoreApplication::translate("QQmlParser","Invalid property type modifier"));
return false;
}
@@ -919,16 +868,6 @@ bool IRBuilder::visit(QQmlJS::AST::UiPublicMember *node)
return false;
}
- Property *property = New<Property>();
- property->flags = 0;
- if (node->isReadonlyMember)
- property->flags |= QV4::CompiledData::Property::IsReadOnly;
- property->type = type;
- if (type >= QV4::CompiledData::Property::Custom)
- property->customTypeNameIndex = registerString(memberType);
- else
- property->customTypeNameIndex = emptyStringIndex;
-
const QString propName = name.toString();
property->nameIndex = registerString(propName);
@@ -969,7 +908,7 @@ bool IRBuilder::visit(QQmlJS::AST::UiPublicMember *node)
bool IRBuilder::visit(QQmlJS::AST::UiSourceElement *node)
{
- if (QQmlJS::AST::FunctionDeclaration *funDecl = QQmlJS::AST::cast<QQmlJS::AST::FunctionDeclaration *>(node->sourceElement)) {
+ if (QQmlJS::AST::FunctionExpression *funDecl = node->sourceElement->asFunctionDefinition()) {
CompiledFunctionOrExpression *foe = New<CompiledFunctionOrExpression>();
foe->node = funDecl;
foe->parentNode = funDecl;
@@ -983,13 +922,16 @@ bool IRBuilder::visit(QQmlJS::AST::UiSourceElement *node)
f->index = index;
f->nameIndex = registerString(funDecl->name.toString());
- const QStringList formals = funDecl->formals ? funDecl->formals->formals() : QStringList();
+ QString returnTypeName = funDecl->typeAnnotation ? funDecl->typeAnnotation->type->toString() : QString();
+ Parameter::initType(&f->returnType, jsGenerator, registerString(returnTypeName));
+
+ const QQmlJS::AST::BoundNames formals = funDecl->formals ? funDecl->formals->formals() : QQmlJS::AST::BoundNames();
int formalsCount = formals.size();
f->formals.allocate(pool, formalsCount);
int i = 0;
- for (const QString &arg : formals) {
- f->formals[i] = registerString(arg);
+ for (const auto &arg : formals) {
+ f->formals[i].init(jsGenerator, arg.id, arg.typeName());
++i;
}
@@ -1022,7 +964,7 @@ QStringRef IRBuilder::asStringRef(QQmlJS::AST::Node *node)
return textRefAt(node->firstSourceLocation(), node->lastSourceLocation());
}
-void IRBuilder::extractVersion(QStringRef string, int *maj, int *min)
+void IRBuilder::extractVersion(const QStringRef &string, int *maj, int *min)
{
*maj = -1; *min = -1;
@@ -1051,7 +993,7 @@ void IRBuilder::setBindingValue(QV4::CompiledData::Binding *binding, QQmlJS::AST
binding->valueLocation.line = loc.startLine;
binding->valueLocation.column = loc.startColumn;
binding->type = QV4::CompiledData::Binding::Type_Invalid;
- if (_propertyDeclaration && (_propertyDeclaration->flags & QV4::CompiledData::Property::IsReadOnly))
+ if (_propertyDeclaration && _propertyDeclaration->isReadOnly)
binding->flags |= QV4::CompiledData::Binding::InitializerForReadOnlyDeclaration;
QQmlJS::AST::ExpressionStatement *exprStmt = QQmlJS::AST::cast<QQmlJS::AST::ExpressionStatement *>(statement);
@@ -1282,7 +1224,7 @@ void IRBuilder::appendBinding(const QQmlJS::AST::SourceLocation &qualifiedNameLo
binding->flags = 0;
- if (_propertyDeclaration && (_propertyDeclaration->flags & QV4::CompiledData::Property::IsReadOnly))
+ if (_propertyDeclaration && _propertyDeclaration->isReadOnly)
binding->flags |= QV4::CompiledData::Binding::InitializerForReadOnlyDeclaration;
// No type name on the initializer means it must be a group property
@@ -1513,7 +1455,8 @@ bool IRBuilder::resolveQualifiedId(QQmlJS::AST::UiQualifiedId **nameToResolve, O
void IRBuilder::recordError(const QQmlJS::AST::SourceLocation &location, const QString &description)
{
QQmlJS::DiagnosticMessage error;
- error.loc = location;
+ error.line = location.startLine;
+ error.column = location.startColumn;
error.message = description;
errors << error;
}
@@ -1545,7 +1488,7 @@ bool IRBuilder::isStatementNodeScript(QQmlJS::AST::Statement *statement)
bool IRBuilder::isRedundantNullInitializerForPropertyDeclaration(Property *property, QQmlJS::AST::Statement *statement)
{
- if (property->type != QV4::CompiledData::Property::Custom)
+ if (property->isBuiltinType || property->isList)
return false;
QQmlJS::AST::ExpressionStatement *exprStmt = QQmlJS::AST::cast<QQmlJS::AST::ExpressionStatement *>(statement);
if (!exprStmt)
@@ -1559,17 +1502,12 @@ void QmlUnitGenerator::generate(Document &output, const QV4::CompiledData::Depen
output.jsGenerator.stringTable.registerString(output.jsModule.fileName);
output.jsGenerator.stringTable.registerString(output.jsModule.finalUrl);
- QQmlRefPointer<QV4::CompiledData::CompilationUnit> compilationUnit = output.javaScriptCompilationUnit;
-
QV4::CompiledData::Unit *jsUnit = nullptr;
- const bool finalize = !compilationUnit->data;
// We may already have unit data if we're loading an ahead-of-time generated cache file.
- if (!finalize) {
- jsUnit = const_cast<QV4::CompiledData::Unit *>(compilationUnit->data);
-#ifndef V4_BOOTSTRAP
- output.javaScriptCompilationUnit->dynamicStrings = output.jsGenerator.stringTable.allStrings();
-#endif
+ if (output.javaScriptCompilationUnit.data) {
+ jsUnit = const_cast<QV4::CompiledData::Unit *>(output.javaScriptCompilationUnit.data);
+ output.javaScriptCompilationUnit.dynamicStrings = output.jsGenerator.stringTable.allStrings();
} else {
QV4::CompiledData::Unit *createdUnit;
jsUnit = createdUnit = output.jsGenerator.generateUnit();
@@ -1581,22 +1519,15 @@ void QmlUnitGenerator::generate(Document &output, const QV4::CompiledData::Depen
break;
}
}
- // This unit's memory was allocated with malloc on the heap, so it's
- // definitely not suitable for StaticData access.
- createdUnit->flags &= ~QV4::CompiledData::Unit::StaticData;
-#ifndef V4_BOOTSTRAP
if (dependencyHasher) {
- QCryptographicHash hash(QCryptographicHash::Md5);
- if (dependencyHasher(&hash)) {
- QByteArray checksum = hash.result();
- Q_ASSERT(checksum.size() == sizeof(createdUnit->dependencyMD5Checksum));
- memcpy(createdUnit->dependencyMD5Checksum, checksum.constData(), sizeof(createdUnit->dependencyMD5Checksum));
+ const QByteArray checksum = dependencyHasher();
+ if (checksum.size() == sizeof(createdUnit->dependencyMD5Checksum)) {
+ memcpy(createdUnit->dependencyMD5Checksum, checksum.constData(),
+ sizeof(createdUnit->dependencyMD5Checksum));
}
}
-#else
- Q_UNUSED(dependencyHasher);
-#endif
+
createdUnit->sourceFileIndex = output.jsGenerator.stringTable.getStringId(output.jsModule.fileName);
createdUnit->finalUrlIndex = output.jsGenerator.stringTable.getStringId(output.jsModule.finalUrl);
}
@@ -1730,7 +1661,7 @@ void QmlUnitGenerator::generate(Document &output, const QV4::CompiledData::Depen
signalToWrite->nParameters = s->parameters->count;
QV4::CompiledData::Parameter *parameterToWrite = reinterpret_cast<QV4::CompiledData::Parameter*>(signalPtr + sizeof(*signalToWrite));
- for (SignalParameter *param = s->parameters->first; param; param = param->next, ++parameterToWrite)
+ for (Parameter *param = s->parameters->first; param; param = param->next, ++parameterToWrite)
*parameterToWrite = *param;
int size = QV4::CompiledData::Signal::calculateSize(s->parameters->count);
@@ -1765,14 +1696,14 @@ void QmlUnitGenerator::generate(Document &output, const QV4::CompiledData::Depen
}
}
- if (finalize) {
+ if (!output.javaScriptCompilationUnit.data) {
// Combine the qml data into the general unit data.
jsUnit = static_cast<QV4::CompiledData::Unit *>(realloc(jsUnit, jsUnit->unitSize + totalSize));
jsUnit->offsetToQmlUnit = jsUnit->unitSize;
jsUnit->unitSize += totalSize;
memcpy(jsUnit->qmlUnit(), qmlUnit, totalSize);
free(qmlUnit);
- jsUnit->generateChecksum();
+ QV4::Compiler::JSUnitGenerator::generateUnitChecksum(jsUnit);
qmlUnit = jsUnit->qmlUnit();
}
@@ -1798,7 +1729,8 @@ void QmlUnitGenerator::generate(Document &output, const QV4::CompiledData::Depen
qDebug() << " " << totalStringSize << "bytes total strings";
}
- compilationUnit->setUnitData(jsUnit, qmlUnit, output.jsModule.fileName, output.jsModule.finalUrl);
+ output.javaScriptCompilationUnit.setUnitData(jsUnit, qmlUnit, output.jsModule.fileName,
+ output.jsModule.finalUrl);
}
char *QmlUnitGenerator::writeBindings(char *bindingPtr, const Object *o, BindingFilter filter) const
@@ -1815,19 +1747,11 @@ char *QmlUnitGenerator::writeBindings(char *bindingPtr, const Object *o, Binding
return bindingPtr;
}
-JSCodeGen::JSCodeGen(const QString &sourceCode, QV4::Compiler::JSUnitGenerator *jsUnitGenerator,
- QV4::Compiler::Module *jsModule, QQmlJS::Engine *jsEngine,
- QQmlJS::AST::UiProgram *qmlRoot,
- const QV4::Compiler::StringTableGenerator *stringPool, const QSet<QString> &globalNames)
- : QV4::Compiler::Codegen(jsUnitGenerator, /*strict mode*/false)
- , sourceCode(sourceCode)
- , jsEngine(jsEngine)
- , qmlRoot(qmlRoot)
- , stringPool(stringPool)
+JSCodeGen::JSCodeGen(Document *document, const QSet<QString> &globalNames)
+ : QV4::Compiler::Codegen(&document->jsGenerator, /*strict mode*/false), document(document)
{
m_globalNames = globalNames;
-
- _module = jsModule;
+ _module = &document->jsModule;
_fileNameIsUrl = true;
}
@@ -1835,18 +1759,18 @@ QVector<int> JSCodeGen::generateJSCodeForFunctionsAndBindings(const QList<Compil
{
auto qmlName = [&](const CompiledFunctionOrExpression &c) {
if (c.nameIndex != 0)
- return stringPool->stringForIndex(c.nameIndex);
+ return document->stringAt(c.nameIndex);
else
return QStringLiteral("%qml-expression-entry");
};
QVector<int> runtimeFunctionIndices(functions.size());
- QV4::Compiler::ScanFunctions scan(this, sourceCode, QV4::Compiler::ContextType::Global);
+ QV4::Compiler::ScanFunctions scan(this, document->code, QV4::Compiler::ContextType::Global);
scan.enterGlobalEnvironment(QV4::Compiler::ContextType::Binding);
for (const CompiledFunctionOrExpression &f : functions) {
- Q_ASSERT(f.node != qmlRoot);
- Q_ASSERT(f.parentNode && f.parentNode != qmlRoot);
- QQmlJS::AST::FunctionDeclaration *function = QQmlJS::AST::cast<QQmlJS::AST::FunctionDeclaration*>(f.node);
+ Q_ASSERT(f.node != document->program);
+ Q_ASSERT(f.parentNode && f.parentNode != document->program);
+ auto function = f.node->asFunctionDefinition();
if (function) {
scan.enterQmlFunction(function);
@@ -1860,7 +1784,7 @@ QVector<int> JSCodeGen::generateJSCodeForFunctionsAndBindings(const QList<Compil
}
scan.leaveEnvironment();
- if (hasError)
+ if (hasError())
return QVector<int>();
_context = nullptr;
@@ -1868,9 +1792,9 @@ QVector<int> JSCodeGen::generateJSCodeForFunctionsAndBindings(const QList<Compil
for (int i = 0; i < functions.count(); ++i) {
const CompiledFunctionOrExpression &qmlFunction = functions.at(i);
QQmlJS::AST::Node *node = qmlFunction.node;
- Q_ASSERT(node != qmlRoot);
+ Q_ASSERT(node != document->program);
- QQmlJS::AST::FunctionDeclaration *function = QQmlJS::AST::cast<QQmlJS::AST::FunctionDeclaration*>(node);
+ QQmlJS::AST::FunctionExpression *function = node->asFunctionDefinition();
QString name;
if (function)
@@ -1883,7 +1807,7 @@ QVector<int> JSCodeGen::generateJSCodeForFunctionsAndBindings(const QList<Compil
body = function->body;
} else {
// Synthesize source elements.
- QQmlJS::MemoryPool *pool = jsEngine->pool();
+ QQmlJS::MemoryPool *pool = document->jsParserEngine.pool();
QQmlJS::AST::Statement *stmt = node->statementCast();
if (!stmt) {
@@ -1904,213 +1828,57 @@ QVector<int> JSCodeGen::generateJSCodeForFunctionsAndBindings(const QList<Compil
return runtimeFunctionIndices;
}
-#ifndef V4_BOOTSTRAP
-
-QQmlPropertyData *PropertyResolver::property(const QString &name, bool *notInRevision, RevisionCheck check) const
-{
- if (notInRevision) *notInRevision = false;
-
- QQmlPropertyData *d = cache->property(name, nullptr, nullptr);
-
- // Find the first property
- while (d && d->isFunction())
- d = cache->overrideData(d);
-
- if (check != IgnoreRevision && d && !cache->isAllowedInRevision(d)) {
- if (notInRevision) *notInRevision = true;
- return nullptr;
- } else {
- return d;
- }
-}
-
-
-QQmlPropertyData *PropertyResolver::signal(const QString &name, bool *notInRevision) const
+bool JSCodeGen::generateCodeForComponents(const QVector<quint32> &componentRoots)
{
- if (notInRevision) *notInRevision = false;
-
- QQmlPropertyData *d = cache->property(name, nullptr, nullptr);
- if (notInRevision) *notInRevision = false;
-
- while (d && !(d->isFunction()))
- d = cache->overrideData(d);
-
- if (d && !cache->isAllowedInRevision(d)) {
- if (notInRevision) *notInRevision = true;
- return nullptr;
- } else if (d && d->isSignal()) {
- return d;
- }
-
- if (name.endsWith(QLatin1String("Changed"))) {
- QString propName = name.mid(0, name.length() - static_cast<int>(strlen("Changed")));
-
- d = property(propName, notInRevision);
- if (d)
- return cache->signal(d->notifyIndex());
+ for (int i = 0; i < componentRoots.count(); ++i) {
+ if (!compileComponent(componentRoots.at(i)))
+ return false;
}
- return nullptr;
-}
-
-IRLoader::IRLoader(const QV4::CompiledData::Unit *qmlData, QmlIR::Document *output)
- : unit(qmlData)
- , output(output)
-{
- pool = output->jsParserEngine.pool();
+ return compileComponent(/*root object*/0);
}
-void IRLoader::load()
+bool JSCodeGen::compileComponent(int contextObject)
{
- output->jsGenerator.stringTable.initializeFromBackingUnit(unit);
-
- const QV4::CompiledData::QmlUnit *qmlUnit = unit->qmlUnit();
-
- for (quint32 i = 0; i < qmlUnit->nImports; ++i)
- output->imports << qmlUnit->importAt(i);
-
- if (unit->flags & QV4::CompiledData::Unit::IsSingleton) {
- QmlIR::Pragma *p = New<QmlIR::Pragma>();
- p->location = QV4::CompiledData::Location();
- p->type = QmlIR::Pragma::PragmaSingleton;
- output->pragmas << p;
+ const QmlIR::Object *obj = document->objects.at(contextObject);
+ if (obj->flags & QV4::CompiledData::Object::IsComponent) {
+ Q_ASSERT(obj->bindingCount() == 1);
+ const QV4::CompiledData::Binding *componentBinding = obj->firstBinding();
+ Q_ASSERT(componentBinding->type == QV4::CompiledData::Binding::Type_Object);
+ contextObject = componentBinding->value.objectIndex;
}
- for (uint i = 0; i < qmlUnit->nObjects; ++i) {
- const QV4::CompiledData::Object *serializedObject = qmlUnit->objectAt(i);
- QmlIR::Object *object = loadObject(serializedObject);
- output->objects.append(object);
- }
+ return compileJavaScriptCodeInObjectsRecursively(contextObject, contextObject);
}
-struct FakeExpression : public QQmlJS::AST::NullExpression
-{
- FakeExpression(int start, int length)
- : location(start, length)
- {}
-
- virtual QQmlJS::AST::SourceLocation firstSourceLocation() const
- { return location; }
-
- virtual QQmlJS::AST::SourceLocation lastSourceLocation() const
- { return location; }
-
-private:
- QQmlJS::AST::SourceLocation location;
-};
-
-QmlIR::Object *IRLoader::loadObject(const QV4::CompiledData::Object *serializedObject)
+bool JSCodeGen::compileJavaScriptCodeInObjectsRecursively(int objectIndex, int scopeObjectIndex)
{
- QmlIR::Object *object = pool->New<QmlIR::Object>();
- object->init(pool, serializedObject->inheritedTypeNameIndex, serializedObject->idNameIndex);
-
- object->indexOfDefaultPropertyOrAlias = serializedObject->indexOfDefaultPropertyOrAlias;
- object->defaultPropertyIsAlias = serializedObject->defaultPropertyIsAlias;
- object->flags = serializedObject->flags;
- object->id = serializedObject->id;
- object->location = serializedObject->location;
- object->locationOfIdProperty = serializedObject->locationOfIdProperty;
-
- QVector<int> functionIndices;
- functionIndices.reserve(serializedObject->nFunctions + serializedObject->nBindings / 2);
-
- for (uint i = 0; i < serializedObject->nBindings; ++i) {
- QmlIR::Binding *b = pool->New<QmlIR::Binding>();
- *static_cast<QV4::CompiledData::Binding*>(b) = serializedObject->bindingTable()[i];
- object->bindings->append(b);
- if (b->type == QV4::CompiledData::Binding::Type_Script) {
- functionIndices.append(b->value.compiledScriptIndex);
- b->value.compiledScriptIndex = functionIndices.count() - 1;
-
- QmlIR::CompiledFunctionOrExpression *foe = pool->New<QmlIR::CompiledFunctionOrExpression>();
- foe->nameIndex = 0;
-
- QQmlJS::AST::ExpressionNode *expr;
-
- if (b->stringIndex != quint32(0)) {
- const int start = output->code.length();
- const QString script = output->stringAt(b->stringIndex);
- const int length = script.length();
- output->code.append(script);
- expr = new (pool) FakeExpression(start, length);
- } else
- expr = new (pool) QQmlJS::AST::NullExpression();
- foe->node = new (pool) QQmlJS::AST::ExpressionStatement(expr); // dummy
- object->functionsAndExpressions->append(foe);
- }
- }
-
- Q_ASSERT(object->functionsAndExpressions->count == functionIndices.count());
+ QmlIR::Object *object = document->objects.at(objectIndex);
+ if (object->flags & QV4::CompiledData::Object::IsComponent)
+ return true;
- for (uint i = 0; i < serializedObject->nSignals; ++i) {
- const QV4::CompiledData::Signal *serializedSignal = serializedObject->signalAt(i);
- QmlIR::Signal *s = pool->New<QmlIR::Signal>();
- s->nameIndex = serializedSignal->nameIndex;
- s->location = serializedSignal->location;
- s->parameters = pool->New<QmlIR::PoolList<QmlIR::SignalParameter> >();
-
- for (uint i = 0; i < serializedSignal->nParameters; ++i) {
- QmlIR::SignalParameter *p = pool->New<QmlIR::SignalParameter>();
- *static_cast<QV4::CompiledData::Parameter*>(p) = *serializedSignal->parameterAt(i);
- s->parameters->append(p);
- }
-
- object->qmlSignals->append(s);
- }
-
- for (uint i = 0; i < serializedObject->nEnums; ++i) {
- const QV4::CompiledData::Enum *serializedEnum = serializedObject->enumAt(i);
- QmlIR::Enum *e = pool->New<QmlIR::Enum>();
- e->nameIndex = serializedEnum->nameIndex;
- e->location = serializedEnum->location;
- e->enumValues = pool->New<QmlIR::PoolList<QmlIR::EnumValue> >();
-
- for (uint i = 0; i < serializedEnum->nEnumValues; ++i) {
- QmlIR::EnumValue *v = pool->New<QmlIR::EnumValue>();
- *static_cast<QV4::CompiledData::EnumValue*>(v) = *serializedEnum->enumValueAt(i);
- e->enumValues->append(v);
- }
-
- object->qmlEnums->append(e);
- }
-
- const QV4::CompiledData::Property *serializedProperty = serializedObject->propertyTable();
- for (uint i = 0; i < serializedObject->nProperties; ++i, ++serializedProperty) {
- QmlIR::Property *p = pool->New<QmlIR::Property>();
- *static_cast<QV4::CompiledData::Property*>(p) = *serializedProperty;
- object->properties->append(p);
- }
+ if (object->functionsAndExpressions->count > 0) {
+ QList<QmlIR::CompiledFunctionOrExpression> functionsToCompile;
+ for (QmlIR::CompiledFunctionOrExpression *foe = object->functionsAndExpressions->first; foe; foe = foe->next)
+ functionsToCompile << *foe;
+ const QVector<int> runtimeFunctionIndices = generateJSCodeForFunctionsAndBindings(functionsToCompile);
+ if (hasError())
+ return false;
- {
- const QV4::CompiledData::Alias *serializedAlias = serializedObject->aliasTable();
- for (uint i = 0; i < serializedObject->nAliases; ++i, ++serializedAlias) {
- QmlIR::Alias *a = pool->New<QmlIR::Alias>();
- *static_cast<QV4::CompiledData::Alias*>(a) = *serializedAlias;
- object->aliases->append(a);
- }
+ object->runtimeFunctionIndices.allocate(document->jsParserEngine.pool(),
+ runtimeFunctionIndices);
}
- const quint32_le *functionIdx = serializedObject->functionOffsetTable();
- for (uint i = 0; i < serializedObject->nFunctions; ++i, ++functionIdx) {
- QmlIR::Function *f = pool->New<QmlIR::Function>();
- const QV4::CompiledData::Function *compiledFunction = unit->functionAt(*functionIdx);
-
- functionIndices.append(*functionIdx);
- f->index = functionIndices.count() - 1;
- f->location = compiledFunction->location;
- f->nameIndex = compiledFunction->nameIndex;
+ for (const QmlIR::Binding *binding = object->firstBinding(); binding; binding = binding->next) {
+ if (binding->type < QV4::CompiledData::Binding::Type_Object)
+ continue;
- f->formals.allocate(pool, int(compiledFunction->nFormals));
- const quint32_le *formalNameIdx = compiledFunction->formalsTable();
- for (uint i = 0; i < compiledFunction->nFormals; ++i, ++formalNameIdx)
- f->formals[i] = *formalNameIdx;
+ int target = binding->value.objectIndex;
+ int scope = binding->type == QV4::CompiledData::Binding::Type_Object ? target : scopeObjectIndex;
- object->functions->append(f);
+ if (!compileJavaScriptCodeInObjectsRecursively(binding->value.objectIndex, scope))
+ return false;
}
- object->runtimeFunctionIndices.allocate(pool, functionIndices);
-
- return object;
+ return true;
}
-
-#endif // V4_BOOTSTRAP
diff --git a/src/qml/compiler/qqmlirbuilder_p.h b/src/qml/compiler/qqmlirbuilder_p.h
index 22bc2d2953..4279f5b768 100644
--- a/src/qml/compiler/qqmlirbuilder_p.h
+++ b/src/qml/compiler/qqmlirbuilder_p.h
@@ -55,25 +55,22 @@
#include <private/qv4compiler_p.h>
#include <private/qv4compileddata_p.h>
#include <private/qqmljsmemorypool_p.h>
+#include <private/qqmljsfixedpoolarray_p.h>
#include <private/qv4codegen_p.h>
#include <private/qv4compiler_p.h>
#include <QTextStream>
#include <QCoreApplication>
-#ifndef V4_BOOTSTRAP
-#include <private/qqmlpropertycache_p.h>
-#endif
-
QT_BEGIN_NAMESPACE
class QQmlPropertyCache;
class QQmlContextData;
class QQmlTypeNameCache;
+struct QQmlIRLoader;
namespace QmlIR {
struct Document;
-struct IRLoader;
template <typename T>
struct PoolList
@@ -219,22 +216,30 @@ struct Enum
};
-struct SignalParameter : public QV4::CompiledData::Parameter
+struct Parameter : public QV4::CompiledData::Parameter
{
- SignalParameter *next;
+ Parameter *next;
+
+ bool init(QV4::Compiler::JSUnitGenerator *stringGenerator, const QString &parameterName, const QString &typeName);
+ static bool init(QV4::CompiledData::Parameter *param, const QV4::Compiler::JSUnitGenerator *stringGenerator,
+ int parameterNameIndex, int typeNameIndex);
+ static bool initType(QV4::CompiledData::ParameterType *paramType,
+ const QV4::Compiler::JSUnitGenerator *stringGenerator, int typeNameIndex);
+
+ static QV4::CompiledData::BuiltinType stringToBuiltinType(const QString &typeName);
};
struct Signal
{
int nameIndex;
QV4::CompiledData::Location location;
- PoolList<SignalParameter> *parameters;
+ PoolList<Parameter> *parameters;
QStringList parameterStringList(const QV4::Compiler::StringTableGenerator *stringPool) const;
int parameterCount() const { return parameters->count; }
- PoolList<SignalParameter>::Iterator parametersBegin() const { return parameters->begin(); }
- PoolList<SignalParameter>::Iterator parametersEnd() const { return parameters->end(); }
+ PoolList<Parameter>::Iterator parametersBegin() const { return parameters->begin(); }
+ PoolList<Parameter>::Iterator parametersEnd() const { return parameters->end(); }
Signal *next;
};
@@ -264,17 +269,18 @@ struct Function
QV4::CompiledData::Location location;
int nameIndex;
quint32 index; // index in parsedQML::functions
- FixedPoolArray<int> formals;
+ QQmlJS::FixedPoolArray<Parameter> formals;
+ QV4::CompiledData::ParameterType returnType;
// --- QQmlPropertyCacheCreator interface
- const int *formalsBegin() const { return formals.begin(); }
- const int *formalsEnd() const { return formals.end(); }
+ const Parameter *formalsBegin() const { return formals.begin(); }
+ const Parameter *formalsEnd() const { return formals.end(); }
// ---
Function *next;
};
-struct Q_QML_PRIVATE_EXPORT CompiledFunctionOrExpression
+struct Q_QMLCOMPILER_PRIVATE_EXPORT CompiledFunctionOrExpression
{
CompiledFunctionOrExpression()
{}
@@ -285,7 +291,7 @@ struct Q_QML_PRIVATE_EXPORT CompiledFunctionOrExpression
CompiledFunctionOrExpression *next = nullptr;
};
-struct Q_QML_PRIVATE_EXPORT Object
+struct Q_QMLCOMPILER_PRIVATE_EXPORT Object
{
Q_DECLARE_TR_FUNCTIONS(Object)
public:
@@ -344,14 +350,14 @@ public:
QString bindingAsString(Document *doc, int scriptIndex) const;
PoolList<CompiledFunctionOrExpression> *functionsAndExpressions;
- FixedPoolArray<int> runtimeFunctionIndices;
+ QQmlJS::FixedPoolArray<int> runtimeFunctionIndices;
- FixedPoolArray<quint32> namedObjectsInComponent;
+ QQmlJS::FixedPoolArray<quint32> namedObjectsInComponent;
int namedObjectsInComponentCount() const { return namedObjectsInComponent.size(); }
const quint32 *namedObjectsInComponentTable() const { return namedObjectsInComponent.begin(); }
private:
- friend struct IRLoader;
+ friend struct ::QQmlIRLoader;
PoolList<Property> *properties;
PoolList<Alias> *aliases;
@@ -361,7 +367,7 @@ private:
PoolList<Function> *functions;
};
-struct Q_QML_PRIVATE_EXPORT Pragma
+struct Q_QMLCOMPILER_PRIVATE_EXPORT Pragma
{
enum PragmaType {
PragmaSingleton = 0x1
@@ -371,7 +377,7 @@ struct Q_QML_PRIVATE_EXPORT Pragma
QV4::CompiledData::Location location;
};
-struct Q_QML_PRIVATE_EXPORT Document
+struct Q_QMLCOMPILER_PRIVATE_EXPORT Document
{
Document(bool debugMode);
QString code;
@@ -383,15 +389,13 @@ struct Q_QML_PRIVATE_EXPORT Document
QVector<Object*> objects;
QV4::Compiler::JSUnitGenerator jsGenerator;
- QQmlRefPointer<QV4::CompiledData::CompilationUnit> javaScriptCompilationUnit;
+ QV4::CompiledData::CompilationUnit javaScriptCompilationUnit;
int registerString(const QString &str) { return jsGenerator.registerString(str); }
QString stringAt(int index) const { return jsGenerator.stringForIndex(index); }
-
- static void removeScriptPragmas(QString &script);
};
-class Q_QML_PRIVATE_EXPORT ScriptDirectivesCollector : public QQmlJS::Directives
+class Q_QMLCOMPILER_PRIVATE_EXPORT ScriptDirectivesCollector : public QQmlJS::Directives
{
QmlIR::Document *document;
QQmlJS::Engine *engine;
@@ -405,7 +409,7 @@ public:
void importModule(const QString &uri, const QString &version, const QString &module, int lineNumber, int column) override;
};
-struct Q_QML_PRIVATE_EXPORT IRBuilder : public QQmlJS::AST::Visitor
+struct Q_QMLCOMPILER_PRIVATE_EXPORT IRBuilder : public QQmlJS::AST::Visitor
{
Q_DECLARE_TR_FUNCTIONS(QQmlCodeGenerator)
public:
@@ -436,7 +440,7 @@ public:
void throwRecursionDepthError() override
{
- recordError(AST::SourceLocation(),
+ recordError(QQmlJS::AST::SourceLocation(),
QStringLiteral("Maximum statement or expression depth exceeded"));
}
@@ -449,19 +453,25 @@ public:
static QString asString(QQmlJS::AST::UiQualifiedId *node);
QStringRef asStringRef(QQmlJS::AST::Node *node);
- static void extractVersion(QStringRef string, int *maj, int *min);
+ static void extractVersion(const QStringRef &string, int *maj, int *min);
QStringRef textRefAt(const QQmlJS::AST::SourceLocation &loc) const
{ return QStringRef(&sourceCode, loc.offset, loc.length); }
QStringRef textRefAt(const QQmlJS::AST::SourceLocation &first,
const QQmlJS::AST::SourceLocation &last) const;
- void setBindingValue(QV4::CompiledData::Binding *binding, QQmlJS::AST::Statement *statement, AST::Node *parentNode);
+ void setBindingValue(QV4::CompiledData::Binding *binding, QQmlJS::AST::Statement *statement,
+ QQmlJS::AST::Node *parentNode);
void tryGeneratingTranslationBinding(const QStringRef &base, QQmlJS::AST::ArgumentList *args, QV4::CompiledData::Binding *binding);
- void appendBinding(QQmlJS::AST::UiQualifiedId *name, QQmlJS::AST::Statement *value, AST::Node *parentNode);
+ void appendBinding(QQmlJS::AST::UiQualifiedId *name, QQmlJS::AST::Statement *value,
+ QQmlJS::AST::Node *parentNode);
void appendBinding(QQmlJS::AST::UiQualifiedId *name, int objectIndex, bool isOnAssignment = false);
- void appendBinding(const QQmlJS::AST::SourceLocation &qualifiedNameLocation, const QQmlJS::AST::SourceLocation &nameLocation, quint32 propertyNameIndex, QQmlJS::AST::Statement *value, AST::Node *parentNode);
- void appendBinding(const QQmlJS::AST::SourceLocation &qualifiedNameLocation, const QQmlJS::AST::SourceLocation &nameLocation, quint32 propertyNameIndex, int objectIndex, bool isListItem = false, bool isOnAssignment = false);
+ void appendBinding(const QQmlJS::AST::SourceLocation &qualifiedNameLocation,
+ const QQmlJS::AST::SourceLocation &nameLocation, quint32 propertyNameIndex,
+ QQmlJS::AST::Statement *value, QQmlJS::AST::Node *parentNode);
+ void appendBinding(const QQmlJS::AST::SourceLocation &qualifiedNameLocation,
+ const QQmlJS::AST::SourceLocation &nameLocation, quint32 propertyNameIndex,
+ int objectIndex, bool isListItem = false, bool isOnAssignment = false);
bool appendAlias(QQmlJS::AST::UiPublicMember *node);
@@ -503,7 +513,7 @@ public:
QV4::Compiler::JSUnitGenerator *jsGenerator;
};
-struct Q_QML_PRIVATE_EXPORT QmlUnitGenerator
+struct Q_QMLCOMPILER_PRIVATE_EXPORT QmlUnitGenerator
{
void generate(Document &output, const QV4::CompiledData::DependentTypesHasher &dependencyHasher = QV4::CompiledData::DependentTypesHasher());
@@ -512,76 +522,23 @@ private:
char *writeBindings(char *bindingPtr, const Object *o, BindingFilter filter) const;
};
-#ifndef V4_BOOTSTRAP
-struct Q_QML_EXPORT PropertyResolver
-{
- PropertyResolver(const QQmlRefPointer<QQmlPropertyCache> &cache)
- : cache(cache)
- {}
-
- QQmlPropertyData *property(int index) const
- {
- return cache->property(index);
- }
-
- enum RevisionCheck {
- CheckRevision,
- IgnoreRevision
- };
-
- QQmlPropertyData *property(const QString &name, bool *notInRevision = nullptr, RevisionCheck check = CheckRevision) const;
-
- // This code must match the semantics of QQmlPropertyPrivate::findSignalByName
- QQmlPropertyData *signal(const QString &name, bool *notInRevision) const;
-
- QQmlRefPointer<QQmlPropertyCache> cache;
-};
-#endif
-
-struct Q_QML_PRIVATE_EXPORT JSCodeGen : public QV4::Compiler::Codegen
+struct Q_QMLCOMPILER_PRIVATE_EXPORT JSCodeGen : public QV4::Compiler::Codegen
{
- JSCodeGen(const QString &sourceCode, QV4::Compiler::JSUnitGenerator *jsUnitGenerator, QV4::Compiler::Module *jsModule,
- QQmlJS::Engine *jsEngine, QQmlJS::AST::UiProgram *qmlRoot,
- const QV4::Compiler::StringTableGenerator *stringPool, const QSet<QString> &globalNames);
+ JSCodeGen(Document *document, const QSet<QString> &globalNames);
// Returns mapping from input functions to index in IR::Module::functions / compiledData->runtimeFunctions
QVector<int> generateJSCodeForFunctionsAndBindings(const QList<CompiledFunctionOrExpression> &functions);
-private:
- QString sourceCode;
- QQmlJS::Engine *jsEngine; // needed for memory pool
- QQmlJS::AST::UiProgram *qmlRoot;
- const QV4::Compiler::StringTableGenerator *stringPool;
-};
-
-struct Q_QML_PRIVATE_EXPORT IRLoader {
- IRLoader(const QV4::CompiledData::Unit *unit, QmlIR::Document *output);
-
- void load();
+ bool generateCodeForComponents(const QVector<quint32> &componentRoots);
+ bool compileComponent(int contextObject);
+ bool compileJavaScriptCodeInObjectsRecursively(int objectIndex, int scopeObjectIndex);
private:
- QmlIR::Object *loadObject(const QV4::CompiledData::Object *serializedObject);
-
- template <typename _Tp> _Tp *New() { return pool->New<_Tp>(); }
-
- const QV4::CompiledData::Unit *unit;
- QmlIR::Document *output;
- QQmlJS::MemoryPool *pool;
+ Document *document;
};
} // namespace QmlIR
-struct QQmlCompileError
-{
- QQmlCompileError() {}
- QQmlCompileError(const QV4::CompiledData::Location &location, const QString &description)
- : location(location), description(description) {}
- QV4::CompiledData::Location location;
- QString description;
-
- bool isSet() const { return !description.isEmpty(); }
-};
-
QT_END_NAMESPACE
#endif // QQMLIRBUILDER_P_H
diff --git a/src/qml/compiler/qqmlpropertycachecreator.cpp b/src/qml/compiler/qqmlpropertycachecreator.cpp
deleted file mode 100644
index fb54da5b73..0000000000
--- a/src/qml/compiler/qqmlpropertycachecreator.cpp
+++ /dev/null
@@ -1,99 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the tools applications 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$
-**
-****************************************************************************/
-
-#include "qqmlpropertycachecreator_p.h"
-
-#include <private/qqmlengine_p.h>
-
-QT_BEGIN_NAMESPACE
-
-QAtomicInt QQmlPropertyCacheCreatorBase::classIndexCounter(0);
-
-QQmlBindingInstantiationContext::QQmlBindingInstantiationContext(int referencingObjectIndex, const QV4::CompiledData::Binding *instantiatingBinding,
- const QString &instantiatingPropertyName, QQmlPropertyCache *referencingObjectPropertyCache)
- : referencingObjectIndex(referencingObjectIndex)
- , instantiatingBinding(instantiatingBinding)
- , instantiatingPropertyName(instantiatingPropertyName)
- , referencingObjectPropertyCache(referencingObjectPropertyCache)
-{
-}
-
-bool QQmlBindingInstantiationContext::resolveInstantiatingProperty()
-{
- if (!instantiatingBinding || instantiatingBinding->type != QV4::CompiledData::Binding::Type_GroupProperty)
- return true;
-
- Q_ASSERT(referencingObjectIndex >= 0);
- Q_ASSERT(referencingObjectPropertyCache);
- Q_ASSERT(instantiatingBinding->propertyNameIndex != 0);
-
- bool notInRevision = false;
- instantiatingProperty = QmlIR::PropertyResolver(referencingObjectPropertyCache).property(instantiatingPropertyName, &notInRevision, QmlIR::PropertyResolver::IgnoreRevision);
- return instantiatingProperty != nullptr;
-}
-
-QQmlRefPointer<QQmlPropertyCache> QQmlBindingInstantiationContext::instantiatingPropertyCache(QQmlEnginePrivate *enginePrivate) const
-{
- if (instantiatingProperty) {
- if (instantiatingProperty->isQObject()) {
- return enginePrivate->rawPropertyCacheForType(instantiatingProperty->propType(), instantiatingProperty->typeMinorVersion());
- } else if (const QMetaObject *vtmo = QQmlValueTypeFactory::metaObjectForMetaType(instantiatingProperty->propType())) {
- return enginePrivate->cache(vtmo, instantiatingProperty->typeMinorVersion());
- }
- }
- return QQmlRefPointer<QQmlPropertyCache>();
-}
-
-void QQmlPendingGroupPropertyBindings::resolveMissingPropertyCaches(QQmlEnginePrivate *enginePrivate, QQmlPropertyCacheVector *propertyCaches) const
-{
- for (QQmlBindingInstantiationContext pendingBinding: *this) {
- const int groupPropertyObjectIndex = pendingBinding.instantiatingBinding->value.objectIndex;
-
- if (propertyCaches->at(groupPropertyObjectIndex))
- continue;
-
- if (!pendingBinding.resolveInstantiatingProperty())
- continue;
-
- auto cache = pendingBinding.instantiatingPropertyCache(enginePrivate);
- propertyCaches->set(groupPropertyObjectIndex, cache);
- }
-}
-
-QT_END_NAMESPACE
diff --git a/src/qml/compiler/qqmlpropertycachecreator_p.h b/src/qml/compiler/qqmlpropertycachecreator_p.h
deleted file mode 100644
index 901602d17b..0000000000
--- a/src/qml/compiler/qqmlpropertycachecreator_p.h
+++ /dev/null
@@ -1,841 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the tools applications 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 QQMLPROPERTYCACHECREATOR_P_H
-#define QQMLPROPERTYCACHECREATOR_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 <private/qqmlvaluetype_p.h>
-#include <private/qqmlengine_p.h>
-
-QT_BEGIN_NAMESPACE
-
-struct QQmlBindingInstantiationContext {
- QQmlBindingInstantiationContext() {}
- QQmlBindingInstantiationContext(int referencingObjectIndex,
- const QV4::CompiledData::Binding *instantiatingBinding,
- const QString &instantiatingPropertyName,
- QQmlPropertyCache *referencingObjectPropertyCache);
-
- bool resolveInstantiatingProperty();
- QQmlRefPointer<QQmlPropertyCache> instantiatingPropertyCache(QQmlEnginePrivate *enginePrivate) const;
-
- int referencingObjectIndex = -1;
- const QV4::CompiledData::Binding *instantiatingBinding = nullptr;
- QString instantiatingPropertyName;
- QQmlRefPointer<QQmlPropertyCache> referencingObjectPropertyCache;
- QQmlPropertyData *instantiatingProperty = nullptr;
-};
-
-struct QQmlPendingGroupPropertyBindings : public QVector<QQmlBindingInstantiationContext>
-{
- void resolveMissingPropertyCaches(QQmlEnginePrivate *enginePrivate, QQmlPropertyCacheVector *propertyCaches) const;
-};
-
-struct QQmlPropertyCacheCreatorBase
-{
- Q_DECLARE_TR_FUNCTIONS(QQmlPropertyCacheCreatorBase)
-public:
- static QAtomicInt classIndexCounter;
-};
-
-template <typename ObjectContainer>
-class QQmlPropertyCacheCreator : public QQmlPropertyCacheCreatorBase
-{
-public:
- typedef typename ObjectContainer::CompiledObject CompiledObject;
-
- QQmlPropertyCacheCreator(QQmlPropertyCacheVector *propertyCaches,
- QQmlPendingGroupPropertyBindings *pendingGroupPropertyBindings,
- QQmlEnginePrivate *enginePrivate,
- const ObjectContainer *objectContainer, const QQmlImports *imports);
-
- QQmlCompileError buildMetaObjects();
-
-protected:
- QQmlCompileError buildMetaObjectRecursively(int objectIndex, const QQmlBindingInstantiationContext &context);
- QQmlRefPointer<QQmlPropertyCache> propertyCacheForObject(const CompiledObject *obj, const QQmlBindingInstantiationContext &context, QQmlCompileError *error) const;
- QQmlCompileError createMetaObject(int objectIndex, const CompiledObject *obj, const QQmlRefPointer<QQmlPropertyCache> &baseTypeCache);
-
- QString stringAt(int index) const { return objectContainer->stringAt(index); }
-
- QQmlEnginePrivate * const enginePrivate;
- const ObjectContainer * const objectContainer;
- const QQmlImports * const imports;
- QQmlPropertyCacheVector *propertyCaches;
- QQmlPendingGroupPropertyBindings *pendingGroupPropertyBindings;
-};
-
-template <typename ObjectContainer>
-inline QQmlPropertyCacheCreator<ObjectContainer>::QQmlPropertyCacheCreator(QQmlPropertyCacheVector *propertyCaches,
- QQmlPendingGroupPropertyBindings *pendingGroupPropertyBindings,
- QQmlEnginePrivate *enginePrivate,
- const ObjectContainer *objectContainer, const QQmlImports *imports)
- : enginePrivate(enginePrivate)
- , objectContainer(objectContainer)
- , imports(imports)
- , propertyCaches(propertyCaches)
- , pendingGroupPropertyBindings(pendingGroupPropertyBindings)
-{
- propertyCaches->resize(objectContainer->objectCount());
-}
-
-template <typename ObjectContainer>
-inline QQmlCompileError QQmlPropertyCacheCreator<ObjectContainer>::buildMetaObjects()
-{
- QQmlBindingInstantiationContext context;
- return buildMetaObjectRecursively(/*root object*/0, context);
-}
-
-template <typename ObjectContainer>
-inline QQmlCompileError QQmlPropertyCacheCreator<ObjectContainer>::buildMetaObjectRecursively(int objectIndex, const QQmlBindingInstantiationContext &context)
-{
- const CompiledObject *obj = objectContainer->objectAt(objectIndex);
-
- bool needVMEMetaObject = obj->propertyCount() != 0 || obj->aliasCount() != 0 || obj->signalCount() != 0 || obj->functionCount() != 0 || obj->enumCount() != 0;
- if (!needVMEMetaObject) {
- auto binding = obj->bindingsBegin();
- auto end = obj->bindingsEnd();
- for ( ; binding != end; ++binding) {
- if (binding->type == QV4::CompiledData::Binding::Type_Object && (binding->flags & QV4::CompiledData::Binding::IsOnAssignment)) {
- // If the on assignment is inside a group property, we need to distinguish between QObject based
- // group properties and value type group properties. For the former the base type is derived from
- // the property that references us, for the latter we only need a meta-object on the referencing object
- // because interceptors can't go to the shared value type instances.
- if (context.instantiatingProperty && QQmlValueTypeFactory::isValueType(context.instantiatingProperty->propType())) {
- if (!propertyCaches->needsVMEMetaObject(context.referencingObjectIndex)) {
- const CompiledObject *obj = objectContainer->objectAt(context.referencingObjectIndex);
- auto *typeRef = objectContainer->resolvedType(obj->inheritedTypeNameIndex);
- Q_ASSERT(typeRef);
- QQmlRefPointer<QQmlPropertyCache> baseTypeCache = typeRef->createPropertyCache(QQmlEnginePrivate::get(enginePrivate));
- QQmlCompileError error = createMetaObject(context.referencingObjectIndex, obj, baseTypeCache);
- if (error.isSet())
- return error;
- }
- } else {
- // On assignments are implemented using value interceptors, which require a VME meta object.
- needVMEMetaObject = true;
- }
- break;
- }
- }
- }
-
- QQmlRefPointer<QQmlPropertyCache> baseTypeCache;
- {
- QQmlCompileError error;
- baseTypeCache = propertyCacheForObject(obj, context, &error);
- if (error.isSet())
- return error;
- }
-
- if (baseTypeCache) {
- if (needVMEMetaObject) {
- QQmlCompileError error = createMetaObject(objectIndex, obj, baseTypeCache);
- if (error.isSet())
- return error;
- } else {
- propertyCaches->set(objectIndex, baseTypeCache);
- }
- }
-
- if (QQmlPropertyCache *thisCache = propertyCaches->at(objectIndex)) {
- auto binding = obj->bindingsBegin();
- auto end = obj->bindingsEnd();
- for ( ; binding != end; ++binding)
- if (binding->type >= QV4::CompiledData::Binding::Type_Object) {
- QQmlBindingInstantiationContext context(objectIndex, &(*binding), stringAt(binding->propertyNameIndex), thisCache);
-
- // Binding to group property where we failed to look up the type of the
- // property? Possibly a group property that is an alias that's not resolved yet.
- // Let's attempt to resolve it after we're done with the aliases and fill in the
- // propertyCaches entry then.
- if (!context.resolveInstantiatingProperty())
- pendingGroupPropertyBindings->append(context);
-
- QQmlCompileError error = buildMetaObjectRecursively(binding->value.objectIndex, context);
- if (error.isSet())
- return error;
- }
- }
-
- QQmlCompileError noError;
- return noError;
-}
-
-template <typename ObjectContainer>
-inline QQmlRefPointer<QQmlPropertyCache> QQmlPropertyCacheCreator<ObjectContainer>::propertyCacheForObject(const CompiledObject *obj, const QQmlBindingInstantiationContext &context, QQmlCompileError *error) const
-{
- if (context.instantiatingProperty) {
- return context.instantiatingPropertyCache(enginePrivate);
- } else if (obj->inheritedTypeNameIndex != 0) {
- auto *typeRef = objectContainer->resolvedType(obj->inheritedTypeNameIndex);
- Q_ASSERT(typeRef);
-
- if (typeRef->isFullyDynamicType) {
- if (obj->propertyCount() > 0 || obj->aliasCount() > 0) {
- *error = QQmlCompileError(obj->location, QQmlPropertyCacheCreatorBase::tr("Fully dynamic types cannot declare new properties."));
- return nullptr;
- }
- if (obj->signalCount() > 0) {
- *error = QQmlCompileError(obj->location, QQmlPropertyCacheCreatorBase::tr("Fully dynamic types cannot declare new signals."));
- return nullptr;
- }
- if (obj->functionCount() > 0) {
- *error = QQmlCompileError(obj->location, QQmlPropertyCacheCreatorBase::tr("Fully Dynamic types cannot declare new functions."));
- return nullptr;
- }
- }
-
- return typeRef->createPropertyCache(QQmlEnginePrivate::get(enginePrivate));
- } else if (context.instantiatingBinding && context.instantiatingBinding->isAttachedProperty()) {
- auto *typeRef = objectContainer->resolvedType(
- context.instantiatingBinding->propertyNameIndex);
- Q_ASSERT(typeRef);
- QQmlType qmltype = typeRef->type;
- if (!qmltype.isValid()) {
- QString propertyName = stringAt(context.instantiatingBinding->propertyNameIndex);
- if (imports->resolveType(propertyName, &qmltype, nullptr, nullptr, nullptr)) {
- if (qmltype.isComposite()) {
- QQmlRefPointer<QQmlTypeData> tdata = enginePrivate->typeLoader.getType(qmltype.sourceUrl());
- Q_ASSERT(tdata);
- Q_ASSERT(tdata->isComplete());
-
- auto compilationUnit = tdata->compilationUnit();
- qmltype = QQmlMetaType::qmlType(compilationUnit->metaTypeId);
- }
- }
- }
-
- const QMetaObject *attachedMo = qmltype.attachedPropertiesType(enginePrivate);
- if (!attachedMo) {
- *error = QQmlCompileError(context.instantiatingBinding->location, QQmlPropertyCacheCreatorBase::tr("Non-existent attached object"));
- return nullptr;
- }
- return enginePrivate->cache(attachedMo);
- }
- return nullptr;
-}
-
-template <typename ObjectContainer>
-inline QQmlCompileError QQmlPropertyCacheCreator<ObjectContainer>::createMetaObject(int objectIndex, const CompiledObject *obj, const QQmlRefPointer<QQmlPropertyCache> &baseTypeCache)
-{
- QQmlRefPointer<QQmlPropertyCache> cache;
- cache.adopt(baseTypeCache->copyAndReserve(obj->propertyCount() + obj->aliasCount(),
- obj->functionCount() + obj->propertyCount() + obj->aliasCount() + obj->signalCount(),
- obj->signalCount() + obj->propertyCount() + obj->aliasCount(), obj->enumCount()));
-
- propertyCaches->set(objectIndex, cache);
- propertyCaches->setNeedsVMEMetaObject(objectIndex);
-
- struct TypeData {
- QV4::CompiledData::Property::Type dtype;
- int metaType;
- } builtinTypes[] = {
- { QV4::CompiledData::Property::Var, QMetaType::QVariant },
- { QV4::CompiledData::Property::Variant, QMetaType::QVariant },
- { QV4::CompiledData::Property::Int, QMetaType::Int },
- { QV4::CompiledData::Property::Bool, QMetaType::Bool },
- { QV4::CompiledData::Property::Real, QMetaType::Double },
- { QV4::CompiledData::Property::String, QMetaType::QString },
- { QV4::CompiledData::Property::Url, QMetaType::QUrl },
- { QV4::CompiledData::Property::Color, QMetaType::QColor },
- { QV4::CompiledData::Property::Font, QMetaType::QFont },
- { QV4::CompiledData::Property::Time, QMetaType::QTime },
- { QV4::CompiledData::Property::Date, QMetaType::QDate },
- { QV4::CompiledData::Property::DateTime, QMetaType::QDateTime },
- { QV4::CompiledData::Property::Rect, QMetaType::QRectF },
- { QV4::CompiledData::Property::Point, QMetaType::QPointF },
- { QV4::CompiledData::Property::Size, QMetaType::QSizeF },
- { QV4::CompiledData::Property::Vector2D, QMetaType::QVector2D },
- { QV4::CompiledData::Property::Vector3D, QMetaType::QVector3D },
- { QV4::CompiledData::Property::Vector4D, QMetaType::QVector4D },
- { QV4::CompiledData::Property::Matrix4x4, QMetaType::QMatrix4x4 },
- { QV4::CompiledData::Property::Quaternion, QMetaType::QQuaternion }
-};
- static const uint builtinTypeCount = sizeof(builtinTypes) / sizeof(TypeData);
-
- QByteArray newClassName;
-
- if (objectIndex == /*root object*/0) {
- const QString path = objectContainer->url().path();
- int lastSlash = path.lastIndexOf(QLatin1Char('/'));
- if (lastSlash > -1) {
- const QStringRef nameBase = path.midRef(lastSlash + 1, path.length() - lastSlash - 5);
- if (!nameBase.isEmpty() && nameBase.at(0).isUpper())
- newClassName = nameBase.toUtf8() + "_QMLTYPE_" +
- QByteArray::number(classIndexCounter.fetchAndAddRelaxed(1));
- }
- }
- if (newClassName.isEmpty()) {
- newClassName = QQmlMetaObject(baseTypeCache.data()).className();
- newClassName.append("_QML_");
- newClassName.append(QByteArray::number(classIndexCounter.fetchAndAddRelaxed(1)));
- }
-
- cache->_dynamicClassName = newClassName;
-
- int varPropCount = 0;
-
- QmlIR::PropertyResolver resolver(baseTypeCache);
-
- auto p = obj->propertiesBegin();
- auto pend = obj->propertiesEnd();
- for ( ; p != pend; ++p) {
- if (p->type == QV4::CompiledData::Property::Var)
- varPropCount++;
-
- bool notInRevision = false;
- QQmlPropertyData *d = resolver.property(stringAt(p->nameIndex), &notInRevision);
- if (d && d->isFinal())
- return QQmlCompileError(p->location, QQmlPropertyCacheCreatorBase::tr("Cannot override FINAL property"));
- }
-
- auto a = obj->aliasesBegin();
- auto aend = obj->aliasesEnd();
- for ( ; a != aend; ++a) {
- bool notInRevision = false;
- QQmlPropertyData *d = resolver.property(stringAt(a->nameIndex), &notInRevision);
- if (d && d->isFinal())
- return QQmlCompileError(a->location, QQmlPropertyCacheCreatorBase::tr("Cannot override FINAL property"));
- }
-
- int effectivePropertyIndex = cache->propertyIndexCacheStart;
- int effectiveMethodIndex = cache->methodIndexCacheStart;
-
- // For property change signal override detection.
- // We prepopulate a set of signal names which already exist in the object,
- // and throw an error if there is a signal/method defined as an override.
- QSet<QString> seenSignals;
- seenSignals << QStringLiteral("destroyed") << QStringLiteral("parentChanged") << QStringLiteral("objectNameChanged");
- QQmlPropertyCache *parentCache = cache.data();
- while ((parentCache = parentCache->parent())) {
- if (int pSigCount = parentCache->signalCount()) {
- int pSigOffset = parentCache->signalOffset();
- for (int i = pSigOffset; i < pSigCount; ++i) {
- QQmlPropertyData *currPSig = parentCache->signal(i);
- // XXX TODO: find a better way to get signal name from the property data :-/
- for (QQmlPropertyCache::StringCache::ConstIterator iter = parentCache->stringCache.begin();
- iter != parentCache->stringCache.end(); ++iter) {
- if (currPSig == (*iter).second) {
- seenSignals.insert(iter.key());
- break;
- }
- }
- }
- }
- }
-
- // Set up notify signals for properties - first normal, then alias
- p = obj->propertiesBegin();
- pend = obj->propertiesEnd();
- for ( ; p != pend; ++p) {
- auto flags = QQmlPropertyData::defaultSignalFlags();
-
- QString changedSigName = stringAt(p->nameIndex) + QLatin1String("Changed");
- seenSignals.insert(changedSigName);
-
- cache->appendSignal(changedSigName, flags, effectiveMethodIndex++);
- }
-
- a = obj->aliasesBegin();
- aend = obj->aliasesEnd();
- for ( ; a != aend; ++a) {
- auto flags = QQmlPropertyData::defaultSignalFlags();
-
- QString changedSigName = stringAt(a->nameIndex) + QLatin1String("Changed");
- seenSignals.insert(changedSigName);
-
- cache->appendSignal(changedSigName, flags, effectiveMethodIndex++);
- }
-
- auto e = obj->enumsBegin();
- auto eend = obj->enumsEnd();
- for ( ; e != eend; ++e) {
- const int enumValueCount = e->enumValueCount();
- QVector<QQmlEnumValue> values;
- values.reserve(enumValueCount);
-
- auto enumValue = e->enumValuesBegin();
- auto end = e->enumValuesEnd();
- for ( ; enumValue != end; ++enumValue)
- values.append(QQmlEnumValue(stringAt(enumValue->nameIndex), enumValue->value));
-
- cache->appendEnum(stringAt(e->nameIndex), values);
- }
-
- // Dynamic signals
- auto s = obj->signalsBegin();
- auto send = obj->signalsEnd();
- for ( ; s != send; ++s) {
- const int paramCount = s->parameterCount();
-
- QList<QByteArray> names;
- names.reserve(paramCount);
- QVarLengthArray<int, 10> paramTypes(paramCount?(paramCount + 1):0);
-
- if (paramCount) {
- paramTypes[0] = paramCount;
-
- int i = 0;
- auto param = s->parametersBegin();
- auto end = s->parametersEnd();
- for ( ; param != end; ++param, ++i) {
- names.append(stringAt(param->nameIndex).toUtf8());
- if (param->type < builtinTypeCount) {
- // built-in type
- paramTypes[i + 1] = builtinTypes[param->type].metaType;
- } else {
- // lazily resolved type
- Q_ASSERT(param->type == QV4::CompiledData::Property::Custom);
- const QString customTypeName = stringAt(param->customTypeNameIndex);
- QQmlType qmltype;
- if (!imports->resolveType(customTypeName, &qmltype, nullptr, nullptr, nullptr))
- return QQmlCompileError(s->location, QQmlPropertyCacheCreatorBase::tr("Invalid signal parameter type: %1").arg(customTypeName));
-
- if (qmltype.isComposite()) {
- QQmlRefPointer<QQmlTypeData> tdata = enginePrivate->typeLoader.getType(qmltype.sourceUrl());
- Q_ASSERT(tdata);
- Q_ASSERT(tdata->isComplete());
-
- auto compilationUnit = tdata->compilationUnit();
-
- paramTypes[i + 1] = compilationUnit->metaTypeId;
- } else {
- paramTypes[i + 1] = qmltype.typeId();
- }
- }
- }
- }
-
- auto flags = QQmlPropertyData::defaultSignalFlags();
- if (paramCount)
- flags.hasArguments = true;
-
- QString signalName = stringAt(s->nameIndex);
- if (seenSignals.contains(signalName))
- return QQmlCompileError(s->location, QQmlPropertyCacheCreatorBase::tr("Duplicate signal name: invalid override of property change signal or superclass signal"));
- seenSignals.insert(signalName);
-
- cache->appendSignal(signalName, flags, effectiveMethodIndex++,
- paramCount?paramTypes.constData():nullptr, names);
- }
-
-
- // Dynamic slots
- auto function = objectContainer->objectFunctionsBegin(obj);
- auto fend = objectContainer->objectFunctionsEnd(obj);
- for ( ; function != fend; ++function) {
- auto flags = QQmlPropertyData::defaultSlotFlags();
-
- const QString slotName = stringAt(function->nameIndex);
- if (seenSignals.contains(slotName))
- return QQmlCompileError(function->location, QQmlPropertyCacheCreatorBase::tr("Duplicate method name: invalid override of property change signal or superclass signal"));
- // Note: we don't append slotName to the seenSignals list, since we don't
- // protect against overriding change signals or methods with properties.
-
- QList<QByteArray> parameterNames;
- auto formal = function->formalsBegin();
- auto end = function->formalsEnd();
- for ( ; formal != end; ++formal) {
- flags.hasArguments = true;
- parameterNames << stringAt(*formal).toUtf8();
- }
-
- cache->appendMethod(slotName, flags, effectiveMethodIndex++, parameterNames);
- }
-
-
- // Dynamic properties
- int effectiveSignalIndex = cache->signalHandlerIndexCacheStart;
- int propertyIdx = 0;
- p = obj->propertiesBegin();
- pend = obj->propertiesEnd();
- for ( ; p != pend; ++p, ++propertyIdx) {
- int propertyType = 0;
- int propertTypeMinorVersion = 0;
- QQmlPropertyData::Flags propertyFlags;
-
- if (p->type == QV4::CompiledData::Property::Var) {
- propertyType = QMetaType::QVariant;
- propertyFlags.type = QQmlPropertyData::Flags::VarPropertyType;
- } else if (p->type < builtinTypeCount) {
- propertyType = builtinTypes[p->type].metaType;
-
- if (p->type == QV4::CompiledData::Property::Variant)
- propertyFlags.type = QQmlPropertyData::Flags::QVariantType;
- } else {
- Q_ASSERT(p->type == QV4::CompiledData::Property::CustomList ||
- p->type == QV4::CompiledData::Property::Custom);
-
- QQmlType qmltype;
- if (!imports->resolveType(stringAt(p->customTypeNameIndex), &qmltype, nullptr, nullptr, nullptr)) {
- return QQmlCompileError(p->location, QQmlPropertyCacheCreatorBase::tr("Invalid property type"));
- }
-
- Q_ASSERT(qmltype.isValid());
- if (qmltype.isComposite()) {
- QQmlRefPointer<QQmlTypeData> tdata = enginePrivate->typeLoader.getType(qmltype.sourceUrl());
- Q_ASSERT(tdata);
- Q_ASSERT(tdata->isComplete());
-
- auto compilationUnit = tdata->compilationUnit();
-
- if (p->type == QV4::CompiledData::Property::Custom) {
- propertyType = compilationUnit->metaTypeId;
- } else {
- propertyType = compilationUnit->listMetaTypeId;
- }
- } else {
- if (p->type == QV4::CompiledData::Property::Custom) {
- propertyType = qmltype.typeId();
- propertTypeMinorVersion = qmltype.minorVersion();
- } else {
- propertyType = qmltype.qListTypeId();
- }
- }
-
- if (p->type == QV4::CompiledData::Property::Custom)
- propertyFlags.type = QQmlPropertyData::Flags::QObjectDerivedType;
- else
- propertyFlags.type = QQmlPropertyData::Flags::QListType;
- }
-
- if (!(p->flags & QV4::CompiledData::Property::IsReadOnly) && p->type != QV4::CompiledData::Property::CustomList)
- propertyFlags.isWritable = true;
-
-
- QString propertyName = stringAt(p->nameIndex);
- if (!obj->defaultPropertyIsAlias && propertyIdx == obj->indexOfDefaultPropertyOrAlias)
- cache->_defaultPropertyName = propertyName;
- cache->appendProperty(propertyName, propertyFlags, effectivePropertyIndex++,
- propertyType, propertTypeMinorVersion, effectiveSignalIndex);
-
- effectiveSignalIndex++;
- }
-
- QQmlCompileError noError;
- return noError;
-}
-
-template <typename ObjectContainer>
-class QQmlPropertyCacheAliasCreator
-{
-public:
- typedef typename ObjectContainer::CompiledObject CompiledObject;
-
- QQmlPropertyCacheAliasCreator(QQmlPropertyCacheVector *propertyCaches, const ObjectContainer *objectContainer);
-
- void appendAliasPropertiesToMetaObjects();
-
- QQmlCompileError appendAliasesToPropertyCache(const CompiledObject &component, int objectIndex);
-
-private:
- void appendAliasPropertiesInMetaObjectsWithinComponent(const CompiledObject &component, int firstObjectIndex);
- QQmlCompileError propertyDataForAlias(const CompiledObject &component, const QV4::CompiledData::Alias &alias, int *type, int *rev, QQmlPropertyRawData::Flags *propertyFlags);
-
- void collectObjectsWithAliasesRecursively(int objectIndex, QVector<int> *objectsWithAliases) const;
-
- int objectForId(const CompiledObject &component, int id) const;
-
- QQmlPropertyCacheVector *propertyCaches;
- const ObjectContainer *objectContainer;
-};
-
-template <typename ObjectContainer>
-inline QQmlPropertyCacheAliasCreator<ObjectContainer>::QQmlPropertyCacheAliasCreator(QQmlPropertyCacheVector *propertyCaches, const ObjectContainer *objectContainer)
- : propertyCaches(propertyCaches)
- , objectContainer(objectContainer)
-{
-
-}
-
-template <typename ObjectContainer>
-inline void QQmlPropertyCacheAliasCreator<ObjectContainer>::appendAliasPropertiesToMetaObjects()
-{
- // skip the root object (index 0) as that one does not have a first object index originating
- // from a binding.
- for (int i = 1; i < objectContainer->objectCount(); ++i) {
- const CompiledObject &component = *objectContainer->objectAt(i);
- if (!(component.flags & QV4::CompiledData::Object::IsComponent))
- continue;
-
- const auto rootBinding = component.bindingsBegin();
- appendAliasPropertiesInMetaObjectsWithinComponent(component, rootBinding->value.objectIndex);
- }
-
- const int rootObjectIndex = 0;
- appendAliasPropertiesInMetaObjectsWithinComponent(*objectContainer->objectAt(rootObjectIndex), rootObjectIndex);
-}
-
-template <typename ObjectContainer>
-inline void QQmlPropertyCacheAliasCreator<ObjectContainer>::appendAliasPropertiesInMetaObjectsWithinComponent(const CompiledObject &component, int firstObjectIndex)
-{
- QVector<int> objectsWithAliases;
- collectObjectsWithAliasesRecursively(firstObjectIndex, &objectsWithAliases);
- if (objectsWithAliases.isEmpty())
- return;
-
- const auto allAliasTargetsExist = [this, &component](const CompiledObject &object) {
- auto alias = object.aliasesBegin();
- auto end = object.aliasesEnd();
- for ( ; alias != end; ++alias) {
- Q_ASSERT(alias->flags & QV4::CompiledData::Alias::Resolved);
-
- const int targetObjectIndex = objectForId(component, alias->targetObjectId);
- Q_ASSERT(targetObjectIndex >= 0);
-
- if (alias->aliasToLocalAlias)
- continue;
-
- if (alias->encodedMetaPropertyIndex == -1)
- continue;
-
- const QQmlPropertyCache *targetCache = propertyCaches->at(targetObjectIndex);
- Q_ASSERT(targetCache);
-
- int coreIndex = QQmlPropertyIndex::fromEncoded(alias->encodedMetaPropertyIndex).coreIndex();
- QQmlPropertyData *targetProperty = targetCache->property(coreIndex);
- if (!targetProperty)
- return false;
- }
- return true;
- };
-
- do {
- QVector<int> pendingObjects;
-
- for (int objectIndex: qAsConst(objectsWithAliases)) {
- const CompiledObject &object = *objectContainer->objectAt(objectIndex);
-
- if (allAliasTargetsExist(object)) {
- appendAliasesToPropertyCache(component, objectIndex);
- } else {
- pendingObjects.append(objectIndex);
- }
-
- }
- qSwap(objectsWithAliases, pendingObjects);
- } while (!objectsWithAliases.isEmpty());
-}
-
-template <typename ObjectContainer>
-inline void QQmlPropertyCacheAliasCreator<ObjectContainer>::collectObjectsWithAliasesRecursively(int objectIndex, QVector<int> *objectsWithAliases) const
-{
- const CompiledObject &object = *objectContainer->objectAt(objectIndex);
- if (object.aliasCount() > 0)
- objectsWithAliases->append(objectIndex);
-
- // Stop at Component boundary
- if (object.flags & QV4::CompiledData::Object::IsComponent && objectIndex != /*root object*/0)
- return;
-
- auto binding = object.bindingsBegin();
- auto end = object.bindingsEnd();
- for (; binding != end; ++binding) {
- if (binding->type != QV4::CompiledData::Binding::Type_Object
- && binding->type != QV4::CompiledData::Binding::Type_AttachedProperty
- && binding->type != QV4::CompiledData::Binding::Type_GroupProperty)
- continue;
-
- collectObjectsWithAliasesRecursively(binding->value.objectIndex, objectsWithAliases);
- }
-}
-
-template <typename ObjectContainer>
-inline QQmlCompileError QQmlPropertyCacheAliasCreator<ObjectContainer>::propertyDataForAlias(
- const CompiledObject &component, const QV4::CompiledData::Alias &alias, int *type, int *minorVersion,
- QQmlPropertyData::Flags *propertyFlags)
-{
- *type = 0;
- bool writable = false;
- bool resettable = false;
-
- propertyFlags->isAlias = true;
-
- if (alias.aliasToLocalAlias) {
- const QV4::CompiledData::Alias *lastAlias = &alias;
- QVarLengthArray<const QV4::CompiledData::Alias *, 4> seenAliases({lastAlias});
-
- do {
- const int targetObjectIndex = objectForId(component, lastAlias->targetObjectId);
- Q_ASSERT(targetObjectIndex >= 0);
- const CompiledObject *targetObject = objectContainer->objectAt(targetObjectIndex);
- Q_ASSERT(targetObject);
-
- auto nextAlias = targetObject->aliasesBegin();
- for (uint i = 0; i < lastAlias->localAliasIndex; ++i)
- ++nextAlias;
-
- const QV4::CompiledData::Alias *targetAlias = &(*nextAlias);
- if (seenAliases.contains(targetAlias)) {
- return QQmlCompileError(targetAlias->location,
- QQmlPropertyCacheCreatorBase::tr("Cyclic alias"));
- }
-
- seenAliases.append(targetAlias);
- lastAlias = targetAlias;
- } while (lastAlias->aliasToLocalAlias);
-
- return propertyDataForAlias(component, *lastAlias, type, minorVersion, propertyFlags);
- }
-
- const int targetObjectIndex = objectForId(component, alias.targetObjectId);
- Q_ASSERT(targetObjectIndex >= 0);
- const CompiledObject &targetObject = *objectContainer->objectAt(targetObjectIndex);
-
- if (alias.encodedMetaPropertyIndex == -1) {
- Q_ASSERT(alias.flags & QV4::CompiledData::Alias::AliasPointsToPointerObject);
- auto *typeRef = objectContainer->resolvedType(targetObject.inheritedTypeNameIndex);
- if (!typeRef) {
- // Can be caused by the alias target not being a valid id or property. E.g.:
- // property alias dataValue: dataVal
- // invalidAliasComponent { id: dataVal }
- return QQmlCompileError(targetObject.location, QQmlPropertyCacheCreatorBase::tr("Invalid alias target"));
- }
-
- if (typeRef->type.isValid())
- *type = typeRef->type.typeId();
- else
- *type = typeRef->compilationUnit->metaTypeId;
-
- *minorVersion = typeRef->minorVersion;
-
- propertyFlags->type = QQmlPropertyData::Flags::QObjectDerivedType;
- } else {
- int coreIndex = QQmlPropertyIndex::fromEncoded(alias.encodedMetaPropertyIndex).coreIndex();
- int valueTypeIndex = QQmlPropertyIndex::fromEncoded(alias.encodedMetaPropertyIndex).valueTypeIndex();
-
- QQmlPropertyCache *targetCache = propertyCaches->at(targetObjectIndex);
- Q_ASSERT(targetCache);
- QQmlPropertyData *targetProperty = targetCache->property(coreIndex);
- Q_ASSERT(targetProperty);
-
- *type = targetProperty->propType();
-
- writable = targetProperty->isWritable();
- resettable = targetProperty->isResettable();
-
- if (valueTypeIndex != -1) {
- const QMetaObject *valueTypeMetaObject = QQmlValueTypeFactory::metaObjectForMetaType(*type);
- if (valueTypeMetaObject->property(valueTypeIndex).isEnumType())
- *type = QVariant::Int;
- else
- *type = valueTypeMetaObject->property(valueTypeIndex).userType();
- } else {
- if (targetProperty->isEnum()) {
- *type = QVariant::Int;
- } else {
- // Copy type flags
- propertyFlags->copyPropertyTypeFlags(targetProperty->flags());
-
- if (targetProperty->isVarProperty())
- propertyFlags->type = QQmlPropertyData::Flags::QVariantType;
- }
- }
- }
-
- propertyFlags->isWritable = !(alias.flags & QV4::CompiledData::Property::IsReadOnly) && writable;
- propertyFlags->isResettable = resettable;
- return QQmlCompileError();
-}
-
-template <typename ObjectContainer>
-inline QQmlCompileError QQmlPropertyCacheAliasCreator<ObjectContainer>::appendAliasesToPropertyCache(
- const CompiledObject &component, int objectIndex)
-{
- const CompiledObject &object = *objectContainer->objectAt(objectIndex);
- if (!object.aliasCount())
- return QQmlCompileError();
-
- QQmlPropertyCache *propertyCache = propertyCaches->at(objectIndex);
- Q_ASSERT(propertyCache);
-
- int effectiveSignalIndex = propertyCache->signalHandlerIndexCacheStart + propertyCache->propertyIndexCache.count();
- int effectivePropertyIndex = propertyCache->propertyIndexCacheStart + propertyCache->propertyIndexCache.count();
-
- int aliasIndex = 0;
- auto alias = object.aliasesBegin();
- auto end = object.aliasesEnd();
- for ( ; alias != end; ++alias, ++aliasIndex) {
- Q_ASSERT(alias->flags & QV4::CompiledData::Alias::Resolved);
-
- int type = 0;
- int minorVersion = 0;
- QQmlPropertyData::Flags propertyFlags;
- QQmlCompileError error = propertyDataForAlias(component, *alias, &type, &minorVersion, &propertyFlags);
- if (error.isSet())
- return error;
-
- const QString propertyName = objectContainer->stringAt(alias->nameIndex);
-
- if (object.defaultPropertyIsAlias && aliasIndex == object.indexOfDefaultPropertyOrAlias)
- propertyCache->_defaultPropertyName = propertyName;
-
- propertyCache->appendProperty(propertyName, propertyFlags, effectivePropertyIndex++,
- type, minorVersion, effectiveSignalIndex++);
- }
-
- return QQmlCompileError();
-}
-
-template <typename ObjectContainer>
-inline int QQmlPropertyCacheAliasCreator<ObjectContainer>::objectForId(const CompiledObject &component, int id) const
-{
- for (quint32 i = 0, count = component.namedObjectsInComponentCount(); i < count; ++i) {
- const int candidateIndex = component.namedObjectsInComponentTable()[i];
- const CompiledObject &candidate = *objectContainer->objectAt(candidateIndex);
- if (candidate.id == id)
- return candidateIndex;
- }
- return -1;
-}
-
-QT_END_NAMESPACE
-
-#endif // QQMLPROPERTYCACHECREATOR_P_H
diff --git a/src/qml/compiler/qqmlpropertyvalidator.cpp b/src/qml/compiler/qqmlpropertyvalidator.cpp
deleted file mode 100644
index d20efe616b..0000000000
--- a/src/qml/compiler/qqmlpropertyvalidator.cpp
+++ /dev/null
@@ -1,727 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the tools applications 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$
-**
-****************************************************************************/
-
-#include "qqmlpropertyvalidator_p.h"
-
-#include <private/qqmlcustomparser_p.h>
-#include <private/qqmlstringconverters_p.h>
-#include <QtCore/qdatetime.h>
-
-QT_BEGIN_NAMESPACE
-
-QQmlPropertyValidator::QQmlPropertyValidator(QQmlEnginePrivate *enginePrivate, const QQmlImports &imports, const QQmlRefPointer<QV4::CompiledData::CompilationUnit> &compilationUnit)
- : enginePrivate(enginePrivate)
- , compilationUnit(compilationUnit)
- , imports(imports)
- , qmlUnit(compilationUnit->unitData())
- , propertyCaches(compilationUnit->propertyCaches)
- , bindingPropertyDataPerObject(&compilationUnit->bindingPropertyDataPerObject)
-{
- bindingPropertyDataPerObject->resize(compilationUnit->objectCount());
-}
-
-QVector<QQmlCompileError> QQmlPropertyValidator::validate()
-{
- return validateObject(/*root object*/0, /*instantiatingBinding*/nullptr);
-}
-
-typedef QVarLengthArray<const QV4::CompiledData::Binding *, 8> GroupPropertyVector;
-
-struct BindingFinder
-{
- bool operator()(quint32 name, const QV4::CompiledData::Binding *binding) const
- {
- return name < binding->propertyNameIndex;
- }
- bool operator()(const QV4::CompiledData::Binding *binding, quint32 name) const
- {
- return binding->propertyNameIndex < name;
- }
- bool operator()(const QV4::CompiledData::Binding *lhs, const QV4::CompiledData::Binding *rhs) const
- {
- return lhs->propertyNameIndex < rhs->propertyNameIndex;
- }
-};
-
-QVector<QQmlCompileError> QQmlPropertyValidator::validateObject(int objectIndex, const QV4::CompiledData::Binding *instantiatingBinding, bool populatingValueTypeGroupProperty) const
-{
- const QV4::CompiledData::Object *obj = compilationUnit->objectAt(objectIndex);
-
- if (obj->flags & QV4::CompiledData::Object::IsComponent) {
- Q_ASSERT(obj->nBindings == 1);
- const QV4::CompiledData::Binding *componentBinding = obj->bindingTable();
- Q_ASSERT(componentBinding->type == QV4::CompiledData::Binding::Type_Object);
- return validateObject(componentBinding->value.objectIndex, componentBinding);
- }
-
- QQmlPropertyCache *propertyCache = propertyCaches.at(objectIndex);
- if (!propertyCache)
- return QVector<QQmlCompileError>();
-
- QQmlCustomParser *customParser = nullptr;
- if (auto typeRef = resolvedType(obj->inheritedTypeNameIndex)) {
- if (typeRef->type.isValid())
- customParser = typeRef->type.customParser();
- }
-
- QList<const QV4::CompiledData::Binding*> customBindings;
-
- // Collect group properties first for sanity checking
- // vector values are sorted by property name string index.
- GroupPropertyVector groupProperties;
- const QV4::CompiledData::Binding *binding = obj->bindingTable();
- for (quint32 i = 0; i < obj->nBindings; ++i, ++binding) {
- if (!binding->isGroupProperty())
- continue;
-
- if (binding->flags & QV4::CompiledData::Binding::IsOnAssignment)
- continue;
-
- if (populatingValueTypeGroupProperty) {
- return recordError(binding->location, tr("Property assignment expected"));
- }
-
- GroupPropertyVector::const_iterator pos = std::lower_bound(groupProperties.constBegin(), groupProperties.constEnd(), binding->propertyNameIndex, BindingFinder());
- groupProperties.insert(pos, binding);
- }
-
- QmlIR::PropertyResolver propertyResolver(propertyCache);
-
- QString defaultPropertyName;
- QQmlPropertyData *defaultProperty = nullptr;
- if (obj->indexOfDefaultPropertyOrAlias != -1) {
- QQmlPropertyCache *cache = propertyCache->parent();
- defaultPropertyName = cache->defaultPropertyName();
- defaultProperty = cache->defaultProperty();
- } else {
- defaultPropertyName = propertyCache->defaultPropertyName();
- defaultProperty = propertyCache->defaultProperty();
- }
-
- QV4::CompiledData::BindingPropertyData collectedBindingPropertyData(obj->nBindings);
-
- binding = obj->bindingTable();
- for (quint32 i = 0; i < obj->nBindings; ++i, ++binding) {
- QString name = stringAt(binding->propertyNameIndex);
-
- if (customParser) {
- if (binding->type == QV4::CompiledData::Binding::Type_AttachedProperty) {
- if (customParser->flags() & QQmlCustomParser::AcceptsAttachedProperties) {
- customBindings << binding;
- continue;
- }
- } else if (QmlIR::IRBuilder::isSignalPropertyName(name)
- && !(customParser->flags() & QQmlCustomParser::AcceptsSignalHandlers)) {
- customBindings << binding;
- continue;
- }
- }
-
- bool bindingToDefaultProperty = false;
- bool isGroupProperty = instantiatingBinding && instantiatingBinding->type == QV4::CompiledData::Binding::Type_GroupProperty;
-
- bool notInRevision = false;
- QQmlPropertyData *pd = nullptr;
- if (!name.isEmpty()) {
- if (binding->flags & QV4::CompiledData::Binding::IsSignalHandlerExpression
- || binding->flags & QV4::CompiledData::Binding::IsSignalHandlerObject) {
- pd = propertyResolver.signal(name, &notInRevision);
- } else {
- pd = propertyResolver.property(name, &notInRevision,
- QmlIR::PropertyResolver::CheckRevision);
- }
-
- if (notInRevision) {
- QString typeName = stringAt(obj->inheritedTypeNameIndex);
- auto *objectType = resolvedType(obj->inheritedTypeNameIndex);
- if (objectType && objectType->type.isValid()) {
- return recordError(binding->location, tr("\"%1.%2\" is not available in %3 %4.%5.").arg(typeName).arg(name).arg(objectType->type.module()).arg(objectType->majorVersion).arg(objectType->minorVersion));
- } else {
- return recordError(binding->location, tr("\"%1.%2\" is not available due to component versioning.").arg(typeName).arg(name));
- }
- }
- } else {
- if (isGroupProperty)
- return recordError(binding->location, tr("Cannot assign a value directly to a grouped property"));
-
- pd = defaultProperty;
- name = defaultPropertyName;
- bindingToDefaultProperty = true;
- }
-
- if (pd)
- collectedBindingPropertyData[i] = pd;
-
- if (name.constData()->isUpper() && !binding->isAttachedProperty()) {
- QQmlType type;
- QQmlImportNamespace *typeNamespace = nullptr;
- imports.resolveType(stringAt(binding->propertyNameIndex), &type, nullptr, nullptr, &typeNamespace);
- if (typeNamespace)
- return recordError(binding->location, tr("Invalid use of namespace"));
- return recordError(binding->location, tr("Invalid attached object assignment"));
- }
-
- if (binding->type >= QV4::CompiledData::Binding::Type_Object && (pd || binding->isAttachedProperty())) {
- const bool populatingValueTypeGroupProperty
- = pd
- && QQmlValueTypeFactory::metaObjectForMetaType(pd->propType())
- && !(binding->flags & QV4::CompiledData::Binding::IsOnAssignment);
- const QVector<QQmlCompileError> subObjectValidatorErrors
- = validateObject(binding->value.objectIndex, binding,
- populatingValueTypeGroupProperty);
- if (!subObjectValidatorErrors.isEmpty())
- return subObjectValidatorErrors;
- }
-
- // Signal handlers were resolved and checked earlier in the signal handler conversion pass.
- if (binding->flags & QV4::CompiledData::Binding::IsSignalHandlerExpression
- || binding->flags & QV4::CompiledData::Binding::IsSignalHandlerObject)
- continue;
-
- if (binding->type == QV4::CompiledData::Binding::Type_AttachedProperty) {
- if (instantiatingBinding && (instantiatingBinding->isAttachedProperty() || instantiatingBinding->isGroupProperty())) {
- return recordError(binding->location, tr("Attached properties cannot be used here"));
- }
- continue;
- }
-
- if (pd) {
- GroupPropertyVector::const_iterator assignedGroupProperty = std::lower_bound(groupProperties.constBegin(), groupProperties.constEnd(), binding->propertyNameIndex, BindingFinder());
- const bool assigningToGroupProperty = assignedGroupProperty != groupProperties.constEnd() && !(binding->propertyNameIndex < (*assignedGroupProperty)->propertyNameIndex);
-
- if (!pd->isWritable()
- && !pd->isQList()
- && !binding->isGroupProperty()
- && !(binding->flags & QV4::CompiledData::Binding::InitializerForReadOnlyDeclaration)
- ) {
-
- if (assigningToGroupProperty && binding->type < QV4::CompiledData::Binding::Type_Object)
- return recordError(binding->valueLocation, tr("Cannot assign a value directly to a grouped property"));
- return recordError(binding->valueLocation, tr("Invalid property assignment: \"%1\" is a read-only property").arg(name));
- }
-
- if (!pd->isQList() && (binding->flags & QV4::CompiledData::Binding::IsListItem)) {
- QString error;
- if (pd->propType() == qMetaTypeId<QQmlScriptString>())
- error = tr( "Cannot assign multiple values to a script property");
- else
- error = tr( "Cannot assign multiple values to a singular property");
- return recordError(binding->valueLocation, error);
- }
-
- if (!bindingToDefaultProperty
- && !binding->isGroupProperty()
- && !(binding->flags & QV4::CompiledData::Binding::IsOnAssignment)
- && assigningToGroupProperty) {
- QV4::CompiledData::Location loc = binding->valueLocation;
- if (loc < (*assignedGroupProperty)->valueLocation)
- loc = (*assignedGroupProperty)->valueLocation;
-
- if (pd && QQmlValueTypeFactory::isValueType(pd->propType()))
- return recordError(loc, tr("Property has already been assigned a value"));
- return recordError(loc, tr("Cannot assign a value directly to a grouped property"));
- }
-
- if (binding->type < QV4::CompiledData::Binding::Type_Script) {
- QQmlCompileError bindingError = validateLiteralBinding(propertyCache, pd, binding);
- if (bindingError.isSet())
- return recordError(bindingError);
- } else if (binding->type == QV4::CompiledData::Binding::Type_Object) {
- QQmlCompileError bindingError = validateObjectBinding(pd, name, binding);
- if (bindingError.isSet())
- return recordError(bindingError);
- } else if (binding->isGroupProperty()) {
- if (QQmlValueTypeFactory::isValueType(pd->propType())) {
- if (QQmlValueTypeFactory::metaObjectForMetaType(pd->propType())) {
- if (!pd->isWritable()) {
- return recordError(binding->location, tr("Invalid property assignment: \"%1\" is a read-only property").arg(name));
- }
- } else {
- return recordError(binding->location, tr("Invalid grouped property access"));
- }
- } else {
- if (!enginePrivate->propertyCacheForType(pd->propType())) {
- return recordError(binding->location,
- tr("Invalid grouped property access: Property \"%1\" with type \"%2\", which is not a value type")
- .arg(name)
- .arg(QString::fromLatin1(QMetaType::typeName(pd->propType())))
- );
- }
- }
- }
- } else {
- if (customParser) {
- customBindings << binding;
- continue;
- }
- if (bindingToDefaultProperty) {
- return recordError(binding->location, tr("Cannot assign to non-existent default property"));
- } else {
- return recordError(binding->location, tr("Cannot assign to non-existent property \"%1\"").arg(name));
- }
- }
- }
-
- if (obj->idNameIndex) {
- if (populatingValueTypeGroupProperty)
- return recordError(obj->locationOfIdProperty, tr("Invalid use of id property with a value type"));
-
- bool notInRevision = false;
- collectedBindingPropertyData << propertyResolver.property(QStringLiteral("id"), &notInRevision);
- }
-
- if (customParser && !customBindings.isEmpty()) {
- customParser->clearErrors();
- customParser->validator = this;
- customParser->engine = enginePrivate;
- customParser->imports = &imports;
- customParser->verifyBindings(compilationUnit, customBindings);
- customParser->validator = nullptr;
- customParser->engine = nullptr;
- customParser->imports = (QQmlImports*)nullptr;
- QVector<QQmlCompileError> parserErrors = customParser->errors();
- if (!parserErrors.isEmpty())
- return parserErrors;
- }
-
- (*bindingPropertyDataPerObject)[objectIndex] = collectedBindingPropertyData;
-
- QVector<QQmlCompileError> noError;
- return noError;
-}
-
-QQmlCompileError QQmlPropertyValidator::validateLiteralBinding(QQmlPropertyCache *propertyCache, QQmlPropertyData *property, const QV4::CompiledData::Binding *binding) const
-{
- if (property->isQList()) {
- return QQmlCompileError(binding->valueLocation, tr("Cannot assign primitives to lists"));
- }
-
- QQmlCompileError noError;
-
- if (property->isEnum()) {
- if (binding->flags & QV4::CompiledData::Binding::IsResolvedEnum)
- return noError;
-
- QString value = binding->valueAsString(compilationUnit.data());
- QMetaProperty p = propertyCache->firstCppMetaObject()->property(property->coreIndex());
- bool ok;
- if (p.isFlagType()) {
- p.enumerator().keysToValue(value.toUtf8().constData(), &ok);
- } else
- p.enumerator().keyToValue(value.toUtf8().constData(), &ok);
-
- if (!ok) {
- return QQmlCompileError(binding->valueLocation, tr("Invalid property assignment: unknown enumeration"));
- }
- return noError;
- }
-
- auto warnOrError = [&](const QString &error) {
- if (binding->type == QV4::CompiledData::Binding::Type_Null) {
- QQmlError warning;
- warning.setUrl(compilationUnit->url());
- warning.setLine(binding->valueLocation.line);
- warning.setColumn(binding->valueLocation.column);
- warning.setDescription(error + tr(" - Assigning null to incompatible properties in QML "
- "is deprecated. This will become a compile error in "
- "future versions of Qt."));
- enginePrivate->warning(warning);
- return noError;
- }
- return QQmlCompileError(binding->valueLocation, error);
- };
-
- switch (property->propType()) {
- case QMetaType::QVariant:
- break;
- case QVariant::String: {
- if (!binding->evaluatesToString()) {
- return warnOrError(tr("Invalid property assignment: string expected"));
- }
- }
- break;
- case QVariant::StringList: {
- if (!binding->evaluatesToString()) {
- return warnOrError(tr("Invalid property assignment: string or string list expected"));
- }
- }
- break;
- case QVariant::ByteArray: {
- if (binding->type != QV4::CompiledData::Binding::Type_String) {
- return warnOrError(tr("Invalid property assignment: byte array expected"));
- }
- }
- break;
- case QVariant::Url: {
- if (binding->type != QV4::CompiledData::Binding::Type_String) {
- return warnOrError(tr("Invalid property assignment: url expected"));
- }
- }
- break;
- case QVariant::UInt: {
- if (binding->type == QV4::CompiledData::Binding::Type_Number) {
- double d = binding->valueAsNumber(compilationUnit->constants);
- if (double(uint(d)) == d)
- return noError;
- }
- return warnOrError(tr("Invalid property assignment: unsigned int expected"));
- }
- break;
- case QVariant::Int: {
- if (binding->type == QV4::CompiledData::Binding::Type_Number) {
- double d = binding->valueAsNumber(compilationUnit->constants);
- if (double(int(d)) == d)
- return noError;
- }
- return warnOrError(tr("Invalid property assignment: int expected"));
- }
- break;
- case QMetaType::Float: {
- if (binding->type != QV4::CompiledData::Binding::Type_Number) {
- return warnOrError(tr("Invalid property assignment: number expected"));
- }
- }
- break;
- case QVariant::Double: {
- if (binding->type != QV4::CompiledData::Binding::Type_Number) {
- return warnOrError(tr("Invalid property assignment: number expected"));
- }
- }
- break;
- case QVariant::Color: {
- bool ok = false;
- QQmlStringConverters::rgbaFromString(binding->valueAsString(compilationUnit.data()), &ok);
- if (!ok) {
- return warnOrError(tr("Invalid property assignment: color expected"));
- }
- }
- break;
-#if QT_CONFIG(datestring)
- case QVariant::Date: {
- bool ok = false;
- QQmlStringConverters::dateFromString(binding->valueAsString(compilationUnit.data()), &ok);
- if (!ok) {
- return warnOrError(tr("Invalid property assignment: date expected"));
- }
- }
- break;
- case QVariant::Time: {
- bool ok = false;
- QQmlStringConverters::timeFromString(binding->valueAsString(compilationUnit.data()), &ok);
- if (!ok) {
- return warnOrError(tr("Invalid property assignment: time expected"));
- }
- }
- break;
- case QVariant::DateTime: {
- bool ok = false;
- QQmlStringConverters::dateTimeFromString(binding->valueAsString(compilationUnit.data()), &ok);
- if (!ok) {
- return warnOrError(tr("Invalid property assignment: datetime expected"));
- }
- }
- break;
-#endif // datestring
- case QVariant::Point: {
- bool ok = false;
- QQmlStringConverters::pointFFromString(binding->valueAsString(compilationUnit.data()), &ok);
- if (!ok) {
- return warnOrError(tr("Invalid property assignment: point expected"));
- }
- }
- break;
- case QVariant::PointF: {
- bool ok = false;
- QQmlStringConverters::pointFFromString(binding->valueAsString(compilationUnit.data()), &ok);
- if (!ok) {
- return warnOrError(tr("Invalid property assignment: point expected"));
- }
- }
- break;
- case QVariant::Size: {
- bool ok = false;
- QQmlStringConverters::sizeFFromString(binding->valueAsString(compilationUnit.data()), &ok);
- if (!ok) {
- return warnOrError(tr("Invalid property assignment: size expected"));
- }
- }
- break;
- case QVariant::SizeF: {
- bool ok = false;
- QQmlStringConverters::sizeFFromString(binding->valueAsString(compilationUnit.data()), &ok);
- if (!ok) {
- return warnOrError(tr("Invalid property assignment: size expected"));
- }
- }
- break;
- case QVariant::Rect: {
- bool ok = false;
- QQmlStringConverters::rectFFromString(binding->valueAsString(compilationUnit.data()), &ok);
- if (!ok) {
- return warnOrError(tr("Invalid property assignment: rect expected"));
- }
- }
- break;
- case QVariant::RectF: {
- bool ok = false;
- QQmlStringConverters::rectFFromString(binding->valueAsString(compilationUnit.data()), &ok);
- if (!ok) {
- return warnOrError(tr("Invalid property assignment: point expected"));
- }
- }
- break;
- case QVariant::Bool: {
- if (binding->type != QV4::CompiledData::Binding::Type_Boolean) {
- return warnOrError(tr("Invalid property assignment: boolean expected"));
- }
- }
- break;
- case QVariant::Vector2D: {
- struct {
- float xp;
- float yp;
- } vec;
- if (!QQmlStringConverters::createFromString(QMetaType::QVector2D, binding->valueAsString(compilationUnit.data()), &vec, sizeof(vec))) {
- return warnOrError(tr("Invalid property assignment: 2D vector expected"));
- }
- }
- break;
- case QVariant::Vector3D: {
- struct {
- float xp;
- float yp;
- float zy;
- } vec;
- if (!QQmlStringConverters::createFromString(QMetaType::QVector3D, binding->valueAsString(compilationUnit.data()), &vec, sizeof(vec))) {
- return warnOrError(tr("Invalid property assignment: 3D vector expected"));
- }
- }
- break;
- case QVariant::Vector4D: {
- struct {
- float xp;
- float yp;
- float zy;
- float wp;
- } vec;
- if (!QQmlStringConverters::createFromString(QMetaType::QVector4D, binding->valueAsString(compilationUnit.data()), &vec, sizeof(vec))) {
- return warnOrError(tr("Invalid property assignment: 4D vector expected"));
- }
- }
- break;
- case QVariant::Quaternion: {
- struct {
- float wp;
- float xp;
- float yp;
- float zp;
- } vec;
- if (!QQmlStringConverters::createFromString(QMetaType::QQuaternion, binding->valueAsString(compilationUnit.data()), &vec, sizeof(vec))) {
- return warnOrError(tr("Invalid property assignment: quaternion expected"));
- }
- }
- break;
- case QVariant::RegExp:
- return warnOrError(tr("Invalid property assignment: regular expression expected; use /pattern/ syntax"));
- default: {
- // generate single literal value assignment to a list property if required
- if (property->propType() == qMetaTypeId<QList<qreal> >()) {
- if (binding->type != QV4::CompiledData::Binding::Type_Number) {
- return warnOrError(tr("Invalid property assignment: number or array of numbers expected"));
- }
- break;
- } else if (property->propType() == qMetaTypeId<QList<int> >()) {
- bool ok = (binding->type == QV4::CompiledData::Binding::Type_Number);
- if (ok) {
- double n = binding->valueAsNumber(compilationUnit->constants);
- if (double(int(n)) != n)
- ok = false;
- }
- if (!ok)
- return warnOrError(tr("Invalid property assignment: int or array of ints expected"));
- break;
- } else if (property->propType() == qMetaTypeId<QList<bool> >()) {
- if (binding->type != QV4::CompiledData::Binding::Type_Boolean) {
- return warnOrError(tr("Invalid property assignment: bool or array of bools expected"));
- }
- break;
- } else if (property->propType() == qMetaTypeId<QList<QUrl> >()) {
- if (binding->type != QV4::CompiledData::Binding::Type_String) {
- return warnOrError(tr("Invalid property assignment: url or array of urls expected"));
- }
- break;
- } else if (property->propType() == qMetaTypeId<QList<QString> >()) {
- if (!binding->evaluatesToString()) {
- return warnOrError(tr("Invalid property assignment: string or array of strings expected"));
- }
- break;
- } else if (property->propType() == qMetaTypeId<QJSValue>()) {
- break;
- } else if (property->propType() == qMetaTypeId<QQmlScriptString>()) {
- break;
- } else if (property->isQObject()
- && binding->type == QV4::CompiledData::Binding::Type_Null) {
- break;
- }
-
- // otherwise, try a custom type assignment
- QQmlMetaType::StringConverter converter = QQmlMetaType::customStringConverter(property->propType());
- if (!converter) {
- return warnOrError(tr("Invalid property assignment: unsupported type \"%1\"").arg(QString::fromLatin1(QMetaType::typeName(property->propType()))));
- }
- }
- break;
- }
- return noError;
-}
-
-/*!
- Returns true if from can be assigned to a (QObject) property of type
- to.
-*/
-bool QQmlPropertyValidator::canCoerce(int to, QQmlPropertyCache *fromMo) const
-{
- QQmlPropertyCache *toMo = enginePrivate->rawPropertyCacheForType(to);
-
- while (fromMo) {
- if (fromMo == toMo)
- return true;
- fromMo = fromMo->parent();
- }
- return false;
-}
-
-QVector<QQmlCompileError> QQmlPropertyValidator::recordError(const QV4::CompiledData::Location &location, const QString &description) const
-{
- QVector<QQmlCompileError> errors;
- errors.append(QQmlCompileError(location, description));
- return errors;
-}
-
-QVector<QQmlCompileError> QQmlPropertyValidator::recordError(const QQmlCompileError &error) const
-{
- QVector<QQmlCompileError> errors;
- errors.append(error);
- return errors;
-}
-
-QQmlCompileError QQmlPropertyValidator::validateObjectBinding(QQmlPropertyData *property, const QString &propertyName, const QV4::CompiledData::Binding *binding) const
-{
- QQmlCompileError noError;
-
- if (binding->flags & QV4::CompiledData::Binding::IsOnAssignment) {
- Q_ASSERT(binding->type == QV4::CompiledData::Binding::Type_Object);
-
- bool isValueSource = false;
- bool isPropertyInterceptor = false;
-
- const QV4::CompiledData::Object *targetObject = compilationUnit->objectAt(binding->value.objectIndex);
- if (auto *typeRef = resolvedType(targetObject->inheritedTypeNameIndex)) {
- QQmlRefPointer<QQmlPropertyCache> cache = typeRef->createPropertyCache(QQmlEnginePrivate::get(enginePrivate));
- const QMetaObject *mo = cache->firstCppMetaObject();
- QQmlType qmlType;
- while (mo && !qmlType.isValid()) {
- qmlType = QQmlMetaType::qmlType(mo);
- mo = mo->superClass();
- }
- Q_ASSERT(qmlType.isValid());
-
- isValueSource = qmlType.propertyValueSourceCast() != -1;
- isPropertyInterceptor = qmlType.propertyValueInterceptorCast() != -1;
- }
-
- if (!isValueSource && !isPropertyInterceptor) {
- return QQmlCompileError(binding->valueLocation, tr("\"%1\" cannot operate on \"%2\"").arg(stringAt(targetObject->inheritedTypeNameIndex)).arg(propertyName));
- }
-
- return noError;
- }
-
- if (QQmlMetaType::isInterface(property->propType())) {
- // Can only check at instantiation time if the created sub-object successfully casts to the
- // target interface.
- return noError;
- } else if (property->propType() == QMetaType::QVariant || property->propType() == qMetaTypeId<QJSValue>()) {
- // We can convert everything to QVariant :)
- return noError;
- } else if (property->isQList()) {
- const int listType = enginePrivate->listType(property->propType());
- if (!QQmlMetaType::isInterface(listType)) {
- QQmlPropertyCache *source = propertyCaches.at(binding->value.objectIndex);
- if (!canCoerce(listType, source)) {
- return QQmlCompileError(binding->valueLocation, tr("Cannot assign object to list property \"%1\"").arg(propertyName));
- }
- }
- return noError;
- } else if (binding->flags & QV4::CompiledData::Binding::IsSignalHandlerObject && property->isFunction()) {
- return noError;
- } else if (QQmlValueTypeFactory::isValueType(property->propType())) {
- auto typeName = QMetaType::typeName(property->propType());
- return QQmlCompileError(binding->location, tr("Can not assign value of type \"%1\" to property \"%2\", expecting an object")
- .arg(typeName ? QString::fromLatin1(typeName) : QString::fromLatin1("<unknown type>"))
- .arg(propertyName));
- } else if (property->propType() == qMetaTypeId<QQmlScriptString>()) {
- return QQmlCompileError(binding->valueLocation, tr("Invalid property assignment: script expected"));
- } else {
- // We want to use the raw metaObject here as the raw metaobject is the
- // actual property type before we applied any extensions that might
- // effect the properties on the type, but don't effect assignability
- // Using -1 for the minor version ensures that we get the raw metaObject.
- QQmlPropertyCache *propertyMetaObject = enginePrivate->rawPropertyCacheForType(property->propType(), -1);
-
- // Will be true if the assigned type inherits propertyMetaObject
- bool isAssignable = false;
- // Determine isAssignable value
- if (propertyMetaObject) {
- QQmlPropertyCache *c = propertyCaches.at(binding->value.objectIndex);
- while (c && !isAssignable) {
- isAssignable |= c == propertyMetaObject;
- c = c->parent();
- }
- }
-
- if (!isAssignable) {
- return QQmlCompileError(binding->valueLocation, tr("Cannot assign object of type \"%1\" to property of type \"%2\" as the former is neither the same as the latter nor a sub-class of it.")
- .arg(stringAt(compilationUnit->objectAt(binding->value.objectIndex)->inheritedTypeNameIndex)).arg(QLatin1String(QMetaType::typeName(property->propType()))));
- }
- }
- return noError;
-}
-
-QT_END_NAMESPACE
diff --git a/src/qml/compiler/qqmlpropertyvalidator_p.h b/src/qml/compiler/qqmlpropertyvalidator_p.h
deleted file mode 100644
index e9ae844ccb..0000000000
--- a/src/qml/compiler/qqmlpropertyvalidator_p.h
+++ /dev/null
@@ -1,91 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the tools applications 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 QQMLPROPERTYVALIDATOR_P_H
-#define QQMLPROPERTYVALIDATOR_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 <private/qqmltypecompiler_p.h>
-
-QT_BEGIN_NAMESPACE
-
-class QQmlPropertyValidator
-{
- Q_DECLARE_TR_FUNCTIONS(QQmlPropertyValidator)
-public:
- QQmlPropertyValidator(QQmlEnginePrivate *enginePrivate, const QQmlImports &imports, const QQmlRefPointer<QV4::CompiledData::CompilationUnit> &compilationUnit);
-
- QVector<QQmlCompileError> validate();
-
-private:
- QVector<QQmlCompileError> validateObject(int objectIndex, const QV4::CompiledData::Binding *instantiatingBinding, bool populatingValueTypeGroupProperty = false) const;
- QQmlCompileError validateLiteralBinding(QQmlPropertyCache *propertyCache, QQmlPropertyData *property, const QV4::CompiledData::Binding *binding) const;
- QQmlCompileError validateObjectBinding(QQmlPropertyData *property, const QString &propertyName, const QV4::CompiledData::Binding *binding) const;
-
- bool canCoerce(int to, QQmlPropertyCache *fromMo) const;
-
- Q_REQUIRED_RESULT QVector<QQmlCompileError> recordError(const QV4::CompiledData::Location &location, const QString &description) const;
- Q_REQUIRED_RESULT QVector<QQmlCompileError> recordError(const QQmlCompileError &error) const;
- QString stringAt(int index) const { return compilationUnit->stringAt(index); }
- QV4::CompiledData::ResolvedTypeReference *resolvedType(int id) const
- {
- return compilationUnit->resolvedType(id);
- }
-
- QQmlEnginePrivate *enginePrivate;
- QQmlRefPointer<QV4::CompiledData::CompilationUnit> compilationUnit;
- const QQmlImports &imports;
- const QV4::CompiledData::Unit *qmlUnit;
- const QQmlPropertyCacheVector &propertyCaches;
-
- QVector<QV4::CompiledData::BindingPropertyData> * const bindingPropertyDataPerObject;
-};
-
-QT_END_NAMESPACE
-
-#endif // QQMLPROPERTYVALIDATOR_P_H
diff --git a/src/qml/compiler/qqmltypecompiler.cpp b/src/qml/compiler/qqmltypecompiler.cpp
deleted file mode 100644
index 66d3afc7a0..0000000000
--- a/src/qml/compiler/qqmltypecompiler.cpp
+++ /dev/null
@@ -1,1420 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the tools applications 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$
-**
-****************************************************************************/
-
-#include "qqmltypecompiler_p.h"
-
-#include <private/qqmlirbuilder_p.h>
-#include <private/qqmlobjectcreator_p.h>
-#include <private/qqmlcustomparser_p.h>
-#include <private/qqmlvmemetaobject_p.h>
-#include <private/qqmlcomponent_p.h>
-#include <private/qqmldelegatecomponent_p.h>
-
-#define COMPILE_EXCEPTION(token, desc) \
- { \
- recordError((token)->location, desc); \
- return false; \
- }
-
-QT_BEGIN_NAMESPACE
-
-QQmlTypeCompiler::QQmlTypeCompiler(QQmlEnginePrivate *engine, QQmlTypeData *typeData,
- QmlIR::Document *parsedQML, const QQmlRefPointer<QQmlTypeNameCache> &typeNameCache,
- QV4::CompiledData::ResolvedTypeReferenceMap *resolvedTypeCache, const QV4::CompiledData::DependentTypesHasher &dependencyHasher)
- : resolvedTypes(resolvedTypeCache)
- , engine(engine)
- , typeData(typeData)
- , dependencyHasher(dependencyHasher)
- , typeNameCache(typeNameCache)
- , document(parsedQML)
-{
-}
-
-QQmlRefPointer<QV4::CompiledData::CompilationUnit> QQmlTypeCompiler::compile()
-{
- // Build property caches and VME meta object data
-
- for (auto it = resolvedTypes->constBegin(), end = resolvedTypes->constEnd();
- it != end; ++it) {
- QQmlCustomParser *customParser = (*it)->type.customParser();
- if (customParser)
- customParsers.insert(it.key(), customParser);
- }
-
- QQmlPendingGroupPropertyBindings pendingGroupPropertyBindings;
-
-
- {
- QQmlPropertyCacheCreator<QQmlTypeCompiler> propertyCacheBuilder(&m_propertyCaches, &pendingGroupPropertyBindings,
- engine, this, imports());
- QQmlCompileError error = propertyCacheBuilder.buildMetaObjects();
- if (error.isSet()) {
- recordError(error);
- return nullptr;
- }
- }
-
- {
- QQmlDefaultPropertyMerger merger(this);
- merger.mergeDefaultProperties();
- }
-
- {
- SignalHandlerConverter converter(this);
- if (!converter.convertSignalHandlerExpressionsToFunctionDeclarations())
- return nullptr;
- }
-
- {
- QQmlEnumTypeResolver enumResolver(this);
- if (!enumResolver.resolveEnumBindings())
- return nullptr;
- }
-
- {
- QQmlCustomParserScriptIndexer cpi(this);
- cpi.annotateBindingsWithScriptStrings();
- }
-
- {
- QQmlAliasAnnotator annotator(this);
- annotator.annotateBindingsToAliases();
- }
-
- // Resolve component boundaries and aliases
-
- {
- // Scan for components, determine their scopes and resolve aliases within the scope.
- QQmlComponentAndAliasResolver resolver(this);
- if (!resolver.resolve())
- return nullptr;
-
- pendingGroupPropertyBindings.resolveMissingPropertyCaches(engine, &m_propertyCaches);
- }
-
- {
- QQmlDeferredAndCustomParserBindingScanner deferredAndCustomParserBindingScanner(this);
- if (!deferredAndCustomParserBindingScanner.scanObject())
- return nullptr;
- }
-
- if (!document->javaScriptCompilationUnit) {
- // Compile JS binding expressions and signal handlers if necessary
- {
- // We can compile script strings ahead of time, but they must be compiled
- // without type optimizations as their scope is always entirely dynamic.
- QQmlScriptStringScanner sss(this);
- sss.scan();
- }
-
- document->jsModule.fileName = typeData->urlString();
- document->jsModule.finalUrl = typeData->finalUrlString();
- QmlIR::JSCodeGen v4CodeGenerator(document->code, &document->jsGenerator, &document->jsModule, &document->jsParserEngine,
- document->program, &document->jsGenerator.stringTable, engine->v8engine()->illegalNames());
- QQmlJSCodeGenerator jsCodeGen(this, &v4CodeGenerator);
- if (!jsCodeGen.generateCodeForComponents())
- return nullptr;
-
- document->javaScriptCompilationUnit = v4CodeGenerator.generateCompilationUnit(/*generated unit data*/false);
- }
-
- // Generate QML compiled type data structures
-
- QmlIR::QmlUnitGenerator qmlGenerator;
- qmlGenerator.generate(*document, dependencyHasher);
-
- QQmlRefPointer<QV4::CompiledData::CompilationUnit> compilationUnit = document->javaScriptCompilationUnit;
- compilationUnit->typeNameCache = typeNameCache;
- compilationUnit->resolvedTypes = *resolvedTypes;
- compilationUnit->propertyCaches = std::move(m_propertyCaches);
- Q_ASSERT(compilationUnit->propertyCaches.count() == static_cast<int>(compilationUnit->objectCount()));
-
- if (errors.isEmpty())
- return compilationUnit;
- else
- return nullptr;
-}
-
-void QQmlTypeCompiler::recordError(QQmlError error)
-{
- error.setUrl(url());
- errors << error;
-}
-
-void QQmlTypeCompiler::recordError(const QV4::CompiledData::Location &location, const QString &description)
-{
- QQmlError error;
- error.setLine(location.line);
- error.setColumn(location.column);
- error.setDescription(description);
- error.setUrl(url());
- errors << error;
-}
-
-void QQmlTypeCompiler::recordError(const QQmlCompileError &error)
-{
- recordError(error.location, error.description);
-}
-
-QString QQmlTypeCompiler::stringAt(int idx) const
-{
- return document->stringAt(idx);
-}
-
-int QQmlTypeCompiler::registerString(const QString &str)
-{
- return document->jsGenerator.registerString(str);
-}
-
-int QQmlTypeCompiler::registerConstant(QV4::ReturnedValue v)
-{
- return document->jsGenerator.registerConstant(v);
-}
-
-const QV4::CompiledData::Unit *QQmlTypeCompiler::qmlUnit() const
-{
- return document->javaScriptCompilationUnit->unitData();
-}
-
-const QQmlImports *QQmlTypeCompiler::imports() const
-{
- return &typeData->imports();
-}
-
-QVector<QmlIR::Object *> *QQmlTypeCompiler::qmlObjects() const
-{
- return &document->objects;
-}
-
-void QQmlTypeCompiler::setPropertyCaches(QQmlPropertyCacheVector &&caches)
-{
- m_propertyCaches = std::move(caches);
- Q_ASSERT(m_propertyCaches.count() > 0);
-}
-
-const QQmlPropertyCacheVector *QQmlTypeCompiler::propertyCaches() const
-{
- return &m_propertyCaches;
-}
-
-QQmlPropertyCacheVector &&QQmlTypeCompiler::takePropertyCaches()
-{
- return std::move(m_propertyCaches);
-}
-
-QQmlJS::MemoryPool *QQmlTypeCompiler::memoryPool()
-{
- return document->jsParserEngine.pool();
-}
-
-QStringRef QQmlTypeCompiler::newStringRef(const QString &string)
-{
- return document->jsParserEngine.newStringRef(string);
-}
-
-const QV4::Compiler::StringTableGenerator *QQmlTypeCompiler::stringPool() const
-{
- return &document->jsGenerator.stringTable;
-}
-
-void QQmlTypeCompiler::setBindingPropertyDataPerObject(const QVector<QV4::CompiledData::BindingPropertyData> &propertyData)
-{
- document->javaScriptCompilationUnit->bindingPropertyDataPerObject = propertyData;
-}
-
-QString QQmlTypeCompiler::bindingAsString(const QmlIR::Object *object, int scriptIndex) const
-{
- return object->bindingAsString(document, scriptIndex);
-}
-
-void QQmlTypeCompiler::addImport(const QString &module, const QString &qualifier, int majorVersion, int minorVersion)
-{
- const quint32 moduleIdx = registerString(module);
- const quint32 qualifierIdx = registerString(qualifier);
-
- for (int i = 0, count = document->imports.count(); i < count; ++i) {
- const QV4::CompiledData::Import *existingImport = document->imports.at(i);
- if (existingImport->type == QV4::CompiledData::Import::ImportLibrary
- && existingImport->uriIndex == moduleIdx
- && existingImport->qualifierIndex == qualifierIdx)
- return;
- }
- auto pool = memoryPool();
- QV4::CompiledData::Import *import = pool->New<QV4::CompiledData::Import>();
- import->type = QV4::CompiledData::Import::ImportLibrary;
- import->majorVersion = majorVersion;
- import->minorVersion = minorVersion;
- import->uriIndex = moduleIdx;
- import->qualifierIndex = qualifierIdx;
- document->imports.append(import);
-}
-
-QQmlCompilePass::QQmlCompilePass(QQmlTypeCompiler *typeCompiler)
- : compiler(typeCompiler)
-{
-}
-
-
-
-SignalHandlerConverter::SignalHandlerConverter(QQmlTypeCompiler *typeCompiler)
- : QQmlCompilePass(typeCompiler)
- , enginePrivate(typeCompiler->enginePrivate())
- , qmlObjects(*typeCompiler->qmlObjects())
- , imports(typeCompiler->imports())
- , customParsers(typeCompiler->customParserCache())
- , illegalNames(typeCompiler->enginePrivate()->v8engine()->illegalNames())
- , propertyCaches(typeCompiler->propertyCaches())
-{
-}
-
-bool SignalHandlerConverter::convertSignalHandlerExpressionsToFunctionDeclarations()
-{
- for (int objectIndex = 0; objectIndex < qmlObjects.count(); ++objectIndex) {
- const QmlIR::Object * const obj = qmlObjects.at(objectIndex);
- QQmlPropertyCache *cache = propertyCaches->at(objectIndex);
- if (!cache)
- continue;
- if (QQmlCustomParser *customParser = customParsers.value(obj->inheritedTypeNameIndex)) {
- if (!(customParser->flags() & QQmlCustomParser::AcceptsSignalHandlers))
- continue;
- }
- const QString elementName = stringAt(obj->inheritedTypeNameIndex);
- if (!convertSignalHandlerExpressionsToFunctionDeclarations(obj, elementName, cache))
- return false;
- }
- return true;
-}
-
-bool SignalHandlerConverter::convertSignalHandlerExpressionsToFunctionDeclarations(const QmlIR::Object *obj, const QString &typeName, QQmlPropertyCache *propertyCache)
-{
- // map from signal name defined in qml itself to list of parameters
- QHash<QString, QStringList> customSignals;
-
- for (QmlIR::Binding *binding = obj->firstBinding(); binding; binding = binding->next) {
- QString propertyName = stringAt(binding->propertyNameIndex);
- // Attached property?
- if (binding->type == QV4::CompiledData::Binding::Type_AttachedProperty) {
- const QmlIR::Object *attachedObj = qmlObjects.at(binding->value.objectIndex);
- auto *typeRef = resolvedType(binding->propertyNameIndex);
- QQmlType type = typeRef ? typeRef->type : QQmlType();
- if (!type.isValid()) {
- if (imports->resolveType(propertyName, &type, nullptr, nullptr, nullptr)) {
- if (type.isComposite()) {
- QQmlRefPointer<QQmlTypeData> tdata = enginePrivate->typeLoader.getType(type.sourceUrl());
- Q_ASSERT(tdata);
- Q_ASSERT(tdata->isComplete());
-
- auto compilationUnit = tdata->compilationUnit();
- type = QQmlMetaType::qmlType(compilationUnit->metaTypeId);
- }
- }
- }
-
- const QMetaObject *attachedType = type.attachedPropertiesType(enginePrivate);
- if (!attachedType)
- COMPILE_EXCEPTION(binding, tr("Non-existent attached object"));
- QQmlPropertyCache *cache = compiler->enginePrivate()->cache(attachedType);
- if (!convertSignalHandlerExpressionsToFunctionDeclarations(attachedObj, propertyName, cache))
- return false;
- continue;
- }
-
- if (!QmlIR::IRBuilder::isSignalPropertyName(propertyName))
- continue;
-
- QmlIR::PropertyResolver resolver(propertyCache);
-
- Q_ASSERT(propertyName.startsWith(QLatin1String("on")));
- propertyName.remove(0, 2);
-
- // Note that the property name could start with any alpha or '_' or '$' character,
- // so we need to do the lower-casing of the first alpha character.
- for (int firstAlphaIndex = 0; firstAlphaIndex < propertyName.size(); ++firstAlphaIndex) {
- if (propertyName.at(firstAlphaIndex).isUpper()) {
- propertyName[firstAlphaIndex] = propertyName.at(firstAlphaIndex).toLower();
- break;
- }
- }
-
- QList<QString> parameters;
-
- bool notInRevision = false;
- QQmlPropertyData *signal = resolver.signal(propertyName, &notInRevision);
- if (signal) {
- int sigIndex = propertyCache->methodIndexToSignalIndex(signal->coreIndex());
- sigIndex = propertyCache->originalClone(sigIndex);
-
- bool unnamedParameter = false;
-
- QList<QByteArray> parameterNames = propertyCache->signalParameterNames(sigIndex);
- for (int i = 0; i < parameterNames.count(); ++i) {
- const QString param = QString::fromUtf8(parameterNames.at(i));
- if (param.isEmpty())
- unnamedParameter = true;
- else if (unnamedParameter) {
- COMPILE_EXCEPTION(binding, tr("Signal uses unnamed parameter followed by named parameter."));
- } else if (illegalNames.contains(param)) {
- COMPILE_EXCEPTION(binding, tr("Signal parameter \"%1\" hides global variable.").arg(param));
- }
- parameters += param;
- }
- } else {
- if (notInRevision) {
- // Try assinging it as a property later
- if (resolver.property(propertyName, /*notInRevision ptr*/nullptr))
- continue;
-
- const QString &originalPropertyName = stringAt(binding->propertyNameIndex);
-
- auto *typeRef = resolvedType(obj->inheritedTypeNameIndex);
- const QQmlType type = typeRef ? typeRef->type : QQmlType();
- if (type.isValid()) {
- COMPILE_EXCEPTION(binding, tr("\"%1.%2\" is not available in %3 %4.%5.").arg(typeName).arg(originalPropertyName).arg(type.module()).arg(type.majorVersion()).arg(type.minorVersion()));
- } else {
- COMPILE_EXCEPTION(binding, tr("\"%1.%2\" is not available due to component versioning.").arg(typeName).arg(originalPropertyName));
- }
- }
-
- // Try to look up the signal parameter names in the object itself
-
- // build cache if necessary
- if (customSignals.isEmpty()) {
- for (const QmlIR::Signal *signal = obj->firstSignal(); signal; signal = signal->next) {
- const QString &signalName = stringAt(signal->nameIndex);
- customSignals.insert(signalName, signal->parameterStringList(compiler->stringPool()));
- }
-
- for (const QmlIR::Property *property = obj->firstProperty(); property; property = property->next) {
- const QString propName = stringAt(property->nameIndex);
- customSignals.insert(propName, QStringList());
- }
- }
-
- QHash<QString, QStringList>::ConstIterator entry = customSignals.constFind(propertyName);
- if (entry == customSignals.constEnd() && propertyName.endsWith(QLatin1String("Changed"))) {
- QString alternateName = propertyName.mid(0, propertyName.length() - static_cast<int>(strlen("Changed")));
- entry = customSignals.constFind(alternateName);
- }
-
- if (entry == customSignals.constEnd()) {
- // Can't find even a custom signal, then just don't do anything and try
- // keeping the binding as a regular property assignment.
- continue;
- }
-
- parameters = entry.value();
- }
-
- // Binding object to signal means connect the signal to the object's default method.
- if (binding->type == QV4::CompiledData::Binding::Type_Object) {
- binding->flags |= QV4::CompiledData::Binding::IsSignalHandlerObject;
- continue;
- }
-
- if (binding->type != QV4::CompiledData::Binding::Type_Script) {
- if (binding->type < QV4::CompiledData::Binding::Type_Script) {
- COMPILE_EXCEPTION(binding, tr("Cannot assign a value to a signal (expecting a script to be run)"));
- } else {
- COMPILE_EXCEPTION(binding, tr("Incorrectly specified signal assignment"));
- }
- }
-
- QQmlJS::MemoryPool *pool = compiler->memoryPool();
-
- QQmlJS::AST::FormalParameterList *paramList = nullptr;
- for (const QString &param : qAsConst(parameters)) {
- QStringRef paramNameRef = compiler->newStringRef(param);
-
- QQmlJS::AST::PatternElement *b = new (pool) QQmlJS::AST::PatternElement(paramNameRef, nullptr);
- paramList = new (pool) QQmlJS::AST::FormalParameterList(paramList, b);
- }
-
- if (paramList)
- paramList = paramList->finish(pool);
-
- QmlIR::CompiledFunctionOrExpression *foe = obj->functionsAndExpressions->slowAt(binding->value.compiledScriptIndex);
- QQmlJS::AST::FunctionDeclaration *functionDeclaration = nullptr;
- if (QQmlJS::AST::ExpressionStatement *es = QQmlJS::AST::cast<QQmlJS::AST::ExpressionStatement*>(foe->node)) {
- if (QQmlJS::AST::FunctionExpression *fe = QQmlJS::AST::cast<QQmlJS::AST::FunctionExpression*>(es->expression)) {
- functionDeclaration = new (pool) QQmlJS::AST::FunctionDeclaration(fe->name, fe->formals, fe->body);
- functionDeclaration->functionToken = fe->functionToken;
- functionDeclaration->identifierToken = fe->identifierToken;
- functionDeclaration->lparenToken = fe->lparenToken;
- functionDeclaration->rparenToken = fe->rparenToken;
- functionDeclaration->lbraceToken = fe->lbraceToken;
- functionDeclaration->rbraceToken = fe->rbraceToken;
- }
- }
- if (!functionDeclaration) {
- QQmlJS::AST::Statement *statement = static_cast<QQmlJS::AST::Statement*>(foe->node);
- QQmlJS::AST::StatementList *body = new (pool) QQmlJS::AST::StatementList(statement);
- body = body->finish();
-
- functionDeclaration = new (pool) QQmlJS::AST::FunctionDeclaration(compiler->newStringRef(stringAt(binding->propertyNameIndex)), paramList, body);
- functionDeclaration->lbraceToken = functionDeclaration->functionToken
- = foe->node->firstSourceLocation();
- functionDeclaration->rbraceToken = foe->node->lastSourceLocation();
- }
- foe->node = functionDeclaration;
- binding->propertyNameIndex = compiler->registerString(propertyName);
- binding->flags |= QV4::CompiledData::Binding::IsSignalHandlerExpression;
- }
- return true;
-}
-
-QQmlEnumTypeResolver::QQmlEnumTypeResolver(QQmlTypeCompiler *typeCompiler)
- : QQmlCompilePass(typeCompiler)
- , qmlObjects(*typeCompiler->qmlObjects())
- , propertyCaches(typeCompiler->propertyCaches())
- , imports(typeCompiler->imports())
-{
-}
-
-bool QQmlEnumTypeResolver::resolveEnumBindings()
-{
- for (int i = 0; i < qmlObjects.count(); ++i) {
- QQmlPropertyCache *propertyCache = propertyCaches->at(i);
- if (!propertyCache)
- continue;
- const QmlIR::Object *obj = qmlObjects.at(i);
-
- QmlIR::PropertyResolver resolver(propertyCache);
-
- for (QmlIR::Binding *binding = obj->firstBinding(); binding; binding = binding->next) {
- if (binding->flags & QV4::CompiledData::Binding::IsSignalHandlerExpression
- || binding->flags & QV4::CompiledData::Binding::IsSignalHandlerObject)
- continue;
-
- if (binding->type != QV4::CompiledData::Binding::Type_Script)
- continue;
-
- const QString propertyName = stringAt(binding->propertyNameIndex);
- bool notInRevision = false;
- QQmlPropertyData *pd = resolver.property(propertyName, &notInRevision);
- if (!pd)
- continue;
-
- if (!pd->isEnum() && pd->propType() != QMetaType::Int)
- continue;
-
- if (!tryQualifiedEnumAssignment(obj, propertyCache, pd, binding))
- return false;
- }
- }
-
- return true;
-}
-
-struct StaticQtMetaObject : public QObject
-{
- static const QMetaObject *get()
- { return &staticQtMetaObject; }
-};
-
-bool QQmlEnumTypeResolver::assignEnumToBinding(QmlIR::Binding *binding, const QStringRef &enumName, int enumValue, bool isQtObject)
-{
- if (enumName.length() > 0 && enumName[0].isLower() && !isQtObject) {
- 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->value.constantValueIndex = compiler->registerConstant(QV4::Encode((double)enumValue));
-// binding->setNumberValueInternal((double)enumValue);
- binding->flags |= QV4::CompiledData::Binding::IsResolvedEnum;
- return true;
-}
-
-bool QQmlEnumTypeResolver::tryQualifiedEnumAssignment(const QmlIR::Object *obj, const QQmlPropertyCache *propertyCache, const QQmlPropertyData *prop, QmlIR::Binding *binding)
-{
- bool isIntProp = (prop->propType() == QMetaType::Int) && !prop->isEnum();
- if (!prop->isEnum() && !isIntProp)
- return true;
-
- if (!prop->isWritable() && !(binding->flags & QV4::CompiledData::Binding::InitializerForReadOnlyDeclaration))
- COMPILE_EXCEPTION(binding, tr("Invalid property assignment: \"%1\" is a read-only property").arg(stringAt(binding->propertyNameIndex)));
-
- Q_ASSERT(binding->type == QV4::CompiledData::Binding::Type_Script);
- const QString string = compiler->bindingAsString(obj, binding->value.compiledScriptIndex);
- if (!string.constData()->isUpper())
- return true;
-
- // we support one or two '.' in the enum phrase:
- // * <TypeName>.<EnumValue>
- // * <TypeName>.<ScopedEnumName>.<EnumValue>
-
- int dot = string.indexOf(QLatin1Char('.'));
- if (dot == -1 || dot == string.length()-1)
- return true;
-
- int dot2 = string.indexOf(QLatin1Char('.'), dot+1);
- if (dot2 != -1 && dot2 != string.length()-1) {
- if (!string.at(dot+1).isUpper())
- return true;
- if (string.indexOf(QLatin1Char('.'), dot2+1) != -1)
- return true;
- }
-
- QHashedStringRef typeName(string.constData(), dot);
- const bool isQtObject = (typeName == QLatin1String("Qt"));
- const QStringRef scopedEnumName = (dot2 != -1 ? string.midRef(dot + 1, dot2 - dot - 1) : QStringRef());
- // ### consider supporting scoped enums in Qt namespace
- const QStringRef enumValue = string.midRef(!isQtObject && dot2 != -1 ? dot2 + 1 : dot + 1);
-
- if (isIntProp) { // ### C++11 allows enums to be other integral types. Should we support other integral types here?
- // Allow enum assignment to ints.
- bool ok;
- int enumval = evaluateEnum(typeName.toString(), scopedEnumName, enumValue, &ok);
- if (ok) {
- if (!assignEnumToBinding(binding, enumValue, enumval, isQtObject))
- return false;
- }
- return true;
- }
- QQmlType type;
- imports->resolveType(typeName, &type, nullptr, nullptr, nullptr);
-
- if (!type.isValid() && !isQtObject)
- return true;
-
- int value = 0;
- bool ok = false;
-
- auto *tr = resolvedType(obj->inheritedTypeNameIndex);
- if (type.isValid() && tr && tr->type == type) {
- // When these two match, we can short cut the search
- QMetaProperty mprop = propertyCache->firstCppMetaObject()->property(prop->coreIndex());
- QMetaEnum menum = mprop.enumerator();
- QByteArray enumName = enumValue.toUtf8();
- if (menum.isScoped() && !scopedEnumName.isEmpty() && enumName != scopedEnumName.toUtf8())
- return true;
-
- if (mprop.isFlagType()) {
- value = menum.keysToValue(enumName.constData(), &ok);
- } else {
- value = menum.keyToValue(enumName.constData(), &ok);
- }
- } else {
- // Otherwise we have to search the whole type
- if (type.isValid()) {
- if (!scopedEnumName.isEmpty())
- value = type.scopedEnumValue(compiler->enginePrivate(), scopedEnumName, enumValue, &ok);
- else
- value = type.enumValue(compiler->enginePrivate(), QHashedStringRef(enumValue), &ok);
- } else {
- QByteArray enumName = enumValue.toUtf8();
- const QMetaObject *metaObject = StaticQtMetaObject::get();
- for (int ii = metaObject->enumeratorCount() - 1; !ok && ii >= 0; --ii) {
- QMetaEnum e = metaObject->enumerator(ii);
- value = e.keyToValue(enumName.constData(), &ok);
- }
- }
- }
-
- if (!ok)
- return true;
-
- return assignEnumToBinding(binding, enumValue, value, isQtObject);
-}
-
-int QQmlEnumTypeResolver::evaluateEnum(const QString &scope, const QStringRef &enumName, const QStringRef &enumValue, bool *ok) const
-{
- Q_ASSERT_X(ok, "QQmlEnumTypeResolver::evaluateEnum", "ok must not be a null pointer");
- *ok = false;
-
- if (scope != QLatin1String("Qt")) {
- QQmlType type;
- imports->resolveType(scope, &type, nullptr, nullptr, nullptr);
- if (!type.isValid())
- return -1;
- if (!enumName.isEmpty())
- return type.scopedEnumValue(compiler->enginePrivate(), enumName, enumValue, ok);
- return type.enumValue(compiler->enginePrivate(), QHashedStringRef(enumValue.constData(), enumValue.length()), ok);
- }
-
- const QMetaObject *mo = StaticQtMetaObject::get();
- int i = mo->enumeratorCount();
- const QByteArray ba = enumValue.toUtf8();
- while (i--) {
- int v = mo->enumerator(i).keyToValue(ba.constData(), ok);
- if (*ok)
- return v;
- }
- return -1;
-}
-
-QQmlCustomParserScriptIndexer::QQmlCustomParserScriptIndexer(QQmlTypeCompiler *typeCompiler)
- : QQmlCompilePass(typeCompiler)
- , qmlObjects(*typeCompiler->qmlObjects())
- , customParsers(typeCompiler->customParserCache())
-{
-}
-
-void QQmlCustomParserScriptIndexer::annotateBindingsWithScriptStrings()
-{
- scanObjectRecursively(/*root object*/0);
-}
-
-void QQmlCustomParserScriptIndexer::scanObjectRecursively(int objectIndex, bool annotateScriptBindings)
-{
- const QmlIR::Object * const obj = qmlObjects.at(objectIndex);
- if (!annotateScriptBindings)
- annotateScriptBindings = customParsers.contains(obj->inheritedTypeNameIndex);
- for (QmlIR::Binding *binding = obj->firstBinding(); binding; binding = binding->next) {
- if (binding->type >= QV4::CompiledData::Binding::Type_Object) {
- scanObjectRecursively(binding->value.objectIndex, annotateScriptBindings);
- continue;
- } else if (binding->type != QV4::CompiledData::Binding::Type_Script)
- continue;
- if (!annotateScriptBindings)
- continue;
- const QString script = compiler->bindingAsString(obj, binding->value.compiledScriptIndex);
- binding->stringIndex = compiler->registerString(script);
- }
-}
-
-QQmlAliasAnnotator::QQmlAliasAnnotator(QQmlTypeCompiler *typeCompiler)
- : QQmlCompilePass(typeCompiler)
- , qmlObjects(*typeCompiler->qmlObjects())
- , propertyCaches(typeCompiler->propertyCaches())
-{
-}
-
-void QQmlAliasAnnotator::annotateBindingsToAliases()
-{
- for (int i = 0; i < qmlObjects.count(); ++i) {
- QQmlPropertyCache *propertyCache = propertyCaches->at(i);
- if (!propertyCache)
- continue;
-
- const QmlIR::Object *obj = qmlObjects.at(i);
-
- QmlIR::PropertyResolver resolver(propertyCache);
- QQmlPropertyData *defaultProperty = obj->indexOfDefaultPropertyOrAlias != -1 ? propertyCache->parent()->defaultProperty() : propertyCache->defaultProperty();
-
- for (QmlIR::Binding *binding = obj->firstBinding(); binding; binding = binding->next) {
- if (!binding->isValueBinding())
- continue;
- bool notInRevision = false;
- QQmlPropertyData *pd = binding->propertyNameIndex != quint32(0) ? resolver.property(stringAt(binding->propertyNameIndex), &notInRevision) : defaultProperty;
- if (pd && pd->isAlias())
- binding->flags |= QV4::CompiledData::Binding::IsBindingToAlias;
- }
- }
-}
-
-QQmlScriptStringScanner::QQmlScriptStringScanner(QQmlTypeCompiler *typeCompiler)
- : QQmlCompilePass(typeCompiler)
- , qmlObjects(*typeCompiler->qmlObjects())
- , propertyCaches(typeCompiler->propertyCaches())
-{
-
-}
-
-void QQmlScriptStringScanner::scan()
-{
- const int scriptStringMetaType = qMetaTypeId<QQmlScriptString>();
- for (int i = 0; i < qmlObjects.count(); ++i) {
- QQmlPropertyCache *propertyCache = propertyCaches->at(i);
- if (!propertyCache)
- continue;
-
- const QmlIR::Object *obj = qmlObjects.at(i);
-
- QmlIR::PropertyResolver resolver(propertyCache);
- QQmlPropertyData *defaultProperty = obj->indexOfDefaultPropertyOrAlias != -1 ? propertyCache->parent()->defaultProperty() : propertyCache->defaultProperty();
-
- for (QmlIR::Binding *binding = obj->firstBinding(); binding; binding = binding->next) {
- if (binding->type != QV4::CompiledData::Binding::Type_Script)
- continue;
- bool notInRevision = false;
- QQmlPropertyData *pd = binding->propertyNameIndex != quint32(0) ? resolver.property(stringAt(binding->propertyNameIndex), &notInRevision) : defaultProperty;
- if (!pd || pd->propType() != scriptStringMetaType)
- continue;
-
- QString script = compiler->bindingAsString(obj, binding->value.compiledScriptIndex);
- binding->stringIndex = compiler->registerString(script);
- }
- }
-}
-
-QQmlComponentAndAliasResolver::QQmlComponentAndAliasResolver(QQmlTypeCompiler *typeCompiler)
- : QQmlCompilePass(typeCompiler)
- , enginePrivate(typeCompiler->enginePrivate())
- , pool(typeCompiler->memoryPool())
- , qmlObjects(typeCompiler->qmlObjects())
- , propertyCaches(std::move(typeCompiler->takePropertyCaches()))
-{
-}
-
-void QQmlComponentAndAliasResolver::findAndRegisterImplicitComponents(const QmlIR::Object *obj, QQmlPropertyCache *propertyCache)
-{
- QmlIR::PropertyResolver propertyResolver(propertyCache);
-
- QQmlPropertyData *defaultProperty = obj->indexOfDefaultPropertyOrAlias != -1 ? propertyCache->parent()->defaultProperty() : propertyCache->defaultProperty();
-
- for (QmlIR::Binding *binding = obj->firstBinding(); binding; binding = binding->next) {
- if (binding->type != QV4::CompiledData::Binding::Type_Object)
- continue;
- if (binding->flags & QV4::CompiledData::Binding::IsSignalHandlerObject)
- continue;
-
- const QmlIR::Object *targetObject = qmlObjects->at(binding->value.objectIndex);
- auto *tr = resolvedType(targetObject->inheritedTypeNameIndex);
- Q_ASSERT(tr);
-
- const QMetaObject *firstMetaObject = nullptr;
- if (tr->type.isValid())
- firstMetaObject = tr->type.metaObject();
- else if (tr->compilationUnit)
- firstMetaObject = tr->compilationUnit->rootPropertyCache()->firstCppMetaObject();
- // 1: test for QQmlComponent
- if (firstMetaObject && firstMetaObject == &QQmlComponent::staticMetaObject)
- continue;
- // 2: test for QQmlAbstractDelegateComponent
- while (firstMetaObject && firstMetaObject != &QQmlAbstractDelegateComponent::staticMetaObject)
- firstMetaObject = firstMetaObject->superClass();
- if (firstMetaObject)
- continue;
- // if here, not a QQmlComponent or a QQmlAbstractDelegateComponent, so needs wrapping
-
- QQmlPropertyData *pd = nullptr;
- if (binding->propertyNameIndex != quint32(0)) {
- bool notInRevision = false;
- pd = propertyResolver.property(stringAt(binding->propertyNameIndex), &notInRevision);
- } else {
- pd = defaultProperty;
- }
- if (!pd || !pd->isQObject())
- continue;
-
- QQmlPropertyCache *pc = enginePrivate->rawPropertyCacheForType(pd->propType(), pd->typeMinorVersion());
- const QMetaObject *mo = pc ? pc->firstCppMetaObject() : nullptr;
- while (mo) {
- if (mo == &QQmlComponent::staticMetaObject)
- break;
- mo = mo->superClass();
- }
-
- if (!mo)
- continue;
-
- // emulate "import Qml 2.0 as QmlInternals" and then wrap the component in "QmlInternals.Component {}"
- QQmlType componentType = QQmlMetaType::qmlType(&QQmlComponent::staticMetaObject);
- Q_ASSERT(componentType.isValid());
- const QString qualifier = QStringLiteral("QmlInternals");
-
- compiler->addImport(componentType.module(), qualifier, componentType.majorVersion(), componentType.minorVersion());
-
- QmlIR::Object *syntheticComponent = pool->New<QmlIR::Object>();
- syntheticComponent->init(pool, compiler->registerString(qualifier + QLatin1Char('.') + componentType.elementName()), compiler->registerString(QString()));
- syntheticComponent->location = binding->valueLocation;
- syntheticComponent->flags |= QV4::CompiledData::Object::IsComponent;
-
- if (!containsResolvedType(syntheticComponent->inheritedTypeNameIndex)) {
- auto typeRef = new QV4::CompiledData::ResolvedTypeReference;
- typeRef->type = componentType;
- typeRef->majorVersion = componentType.majorVersion();
- typeRef->minorVersion = componentType.minorVersion();
- insertResolvedType(syntheticComponent->inheritedTypeNameIndex, typeRef);
- }
-
- qmlObjects->append(syntheticComponent);
- const int componentIndex = qmlObjects->count() - 1;
- // Keep property caches symmetric
- QQmlPropertyCache *componentCache = enginePrivate->cache(&QQmlComponent::staticMetaObject);
- propertyCaches.append(componentCache);
-
- QmlIR::Binding *syntheticBinding = pool->New<QmlIR::Binding>();
- *syntheticBinding = *binding;
- syntheticBinding->type = QV4::CompiledData::Binding::Type_Object;
- QString error = syntheticComponent->appendBinding(syntheticBinding, /*isListBinding*/false);
- Q_ASSERT(error.isEmpty());
- Q_UNUSED(error);
-
- binding->value.objectIndex = componentIndex;
-
- componentRoots.append(componentIndex);
- }
-}
-
-bool QQmlComponentAndAliasResolver::resolve()
-{
- // Detect real Component {} objects as well as implicitly defined components, such as
- // someItemDelegate: Item {}
- // In the implicit case Item is surrounded by a synthetic Component {} because the property
- // on the left hand side is of QQmlComponent type.
- const int objCountWithoutSynthesizedComponents = qmlObjects->count();
- for (int i = 0; i < objCountWithoutSynthesizedComponents; ++i) {
- QmlIR::Object *obj = qmlObjects->at(i);
- QQmlPropertyCache *cache = propertyCaches.at(i);
- if (obj->inheritedTypeNameIndex == 0 && !cache)
- continue;
-
- bool isExplicitComponent = false;
-
- if (obj->inheritedTypeNameIndex) {
- auto *tref = resolvedType(obj->inheritedTypeNameIndex);
- Q_ASSERT(tref);
- if (tref->type.metaObject() == &QQmlComponent::staticMetaObject)
- isExplicitComponent = true;
- }
- if (!isExplicitComponent) {
- if (cache)
- findAndRegisterImplicitComponents(obj, cache);
- continue;
- }
-
- obj->flags |= QV4::CompiledData::Object::IsComponent;
-
- if (obj->functionCount() > 0)
- COMPILE_EXCEPTION(obj, tr("Component objects cannot declare new functions."));
- if (obj->propertyCount() > 0 || obj->aliasCount() > 0)
- COMPILE_EXCEPTION(obj, tr("Component objects cannot declare new properties."));
- if (obj->signalCount() > 0)
- COMPILE_EXCEPTION(obj, tr("Component objects cannot declare new signals."));
-
- if (obj->bindingCount() == 0)
- COMPILE_EXCEPTION(obj, tr("Cannot create empty component specification"));
-
- const QmlIR::Binding *rootBinding = obj->firstBinding();
-
- for (const QmlIR::Binding *b = rootBinding; b; b = b->next) {
- if (b->propertyNameIndex != 0)
- COMPILE_EXCEPTION(rootBinding, tr("Component elements may not contain properties other than id"));
- }
-
- if (rootBinding->next || rootBinding->type != QV4::CompiledData::Binding::Type_Object)
- COMPILE_EXCEPTION(obj, tr("Invalid component body specification"));
-
- // For the root object, we are going to collect ids/aliases and resolve them for as a separate
- // last pass.
- if (i != 0)
- componentRoots.append(i);
-
- }
-
- for (int i = 0; i < componentRoots.count(); ++i) {
- QmlIR::Object *component = qmlObjects->at(componentRoots.at(i));
- const QmlIR::Binding *rootBinding = component->firstBinding();
-
- _idToObjectIndex.clear();
-
- _objectsWithAliases.clear();
-
- if (!collectIdsAndAliases(rootBinding->value.objectIndex))
- return false;
-
- component->namedObjectsInComponent.allocate(pool, _idToObjectIndex);
-
- if (!resolveAliases(componentRoots.at(i)))
- return false;
- }
-
- // Collect ids and aliases for root
- _idToObjectIndex.clear();
- _objectsWithAliases.clear();
-
- collectIdsAndAliases(/*root object*/0);
-
- QmlIR::Object *rootComponent = qmlObjects->at(/*root object*/0);
- rootComponent->namedObjectsInComponent.allocate(pool, _idToObjectIndex);
-
- if (!resolveAliases(/*root object*/0))
- return false;
-
- // Implicit component insertion may have added objects and thus we also need
- // to extend the symmetric propertyCaches.
- compiler->setPropertyCaches(std::move(propertyCaches));
- compiler->setComponentRoots(componentRoots);
-
- return true;
-}
-
-bool QQmlComponentAndAliasResolver::collectIdsAndAliases(int objectIndex)
-{
- QmlIR::Object *obj = qmlObjects->at(objectIndex);
-
- if (obj->idNameIndex != 0) {
- if (_idToObjectIndex.contains(obj->idNameIndex)) {
- recordError(obj->locationOfIdProperty, tr("id is not unique"));
- return false;
- }
- obj->id = _idToObjectIndex.count();
- _idToObjectIndex.insert(obj->idNameIndex, objectIndex);
- }
-
- if (obj->aliasCount() > 0)
- _objectsWithAliases.append(objectIndex);
-
- // Stop at Component boundary
- if (obj->flags & QV4::CompiledData::Object::IsComponent && objectIndex != /*root object*/0)
- return true;
-
- for (const QmlIR::Binding *binding = obj->firstBinding(); binding; binding = binding->next) {
- if (binding->type != QV4::CompiledData::Binding::Type_Object
- && binding->type != QV4::CompiledData::Binding::Type_AttachedProperty
- && binding->type != QV4::CompiledData::Binding::Type_GroupProperty)
- continue;
-
- if (!collectIdsAndAliases(binding->value.objectIndex))
- return false;
- }
-
- return true;
-}
-
-bool QQmlComponentAndAliasResolver::resolveAliases(int componentIndex)
-{
- if (_objectsWithAliases.isEmpty())
- return true;
-
- QQmlPropertyCacheAliasCreator<QQmlTypeCompiler> aliasCacheCreator(&propertyCaches, compiler);
-
- bool atLeastOneAliasResolved;
- do {
- atLeastOneAliasResolved = false;
- QVector<int> pendingObjects;
-
- for (int objectIndex: qAsConst(_objectsWithAliases)) {
-
- QQmlCompileError error;
- const auto result = resolveAliasesInObject(objectIndex, &error);
-
- if (error.isSet()) {
- recordError(error);
- return false;
- }
-
- if (result == AllAliasesResolved) {
- QQmlCompileError error = aliasCacheCreator.appendAliasesToPropertyCache(*qmlObjects->at(componentIndex), objectIndex);
- if (error.isSet()) {
- recordError(error);
- return false;
- }
- atLeastOneAliasResolved = true;
- } else if (result == SomeAliasesResolved) {
- atLeastOneAliasResolved = true;
- pendingObjects.append(objectIndex);
- } else {
- pendingObjects.append(objectIndex);
- }
- }
- qSwap(_objectsWithAliases, pendingObjects);
- } while (!_objectsWithAliases.isEmpty() && atLeastOneAliasResolved);
-
- if (!atLeastOneAliasResolved && !_objectsWithAliases.isEmpty()) {
- const QmlIR::Object *obj = qmlObjects->at(_objectsWithAliases.first());
- for (auto alias = obj->aliasesBegin(), end = obj->aliasesEnd(); alias != end; ++alias) {
- if (!(alias->flags & QV4::CompiledData::Alias::Resolved)) {
- recordError(alias->location, tr("Circular alias reference detected"));
- return false;
- }
- }
- }
-
- return true;
-}
-
-QQmlComponentAndAliasResolver::AliasResolutionResult QQmlComponentAndAliasResolver::resolveAliasesInObject(int objectIndex, QQmlCompileError *error)
-{
- const QmlIR::Object * const obj = qmlObjects->at(objectIndex);
- if (!obj->aliasCount())
- return AllAliasesResolved;
-
- int numResolvedAliases = 0;
- bool seenUnresolvedAlias = false;
-
- for (QmlIR::Alias *alias = obj->firstAlias(); alias; alias = alias->next) {
- if (alias->flags & QV4::CompiledData::Alias::Resolved)
- continue;
-
- seenUnresolvedAlias = true;
-
- const int idIndex = alias->idIndex;
- const int targetObjectIndex = _idToObjectIndex.value(idIndex, -1);
- if (targetObjectIndex == -1) {
- *error = QQmlCompileError(alias->referenceLocation, tr("Invalid alias reference. Unable to find id \"%1\"").arg(stringAt(idIndex)));
- break;
- }
-
- const QmlIR::Object *targetObject = qmlObjects->at(targetObjectIndex);
- Q_ASSERT(targetObject->id >= 0);
- alias->targetObjectId = targetObject->id;
- alias->aliasToLocalAlias = false;
-
- const QString aliasPropertyValue = stringAt(alias->propertyNameIndex);
-
- QStringRef property;
- QStringRef subProperty;
-
- const int propertySeparator = aliasPropertyValue.indexOf(QLatin1Char('.'));
- if (propertySeparator != -1) {
- property = aliasPropertyValue.leftRef(propertySeparator);
- subProperty = aliasPropertyValue.midRef(propertySeparator + 1);
- } else
- property = QStringRef(&aliasPropertyValue, 0, aliasPropertyValue.length());
-
- QQmlPropertyIndex propIdx;
-
- if (property.isEmpty()) {
- alias->flags |= QV4::CompiledData::Alias::AliasPointsToPointerObject;
- } else {
- QQmlPropertyCache *targetCache = propertyCaches.at(targetObjectIndex);
- if (!targetCache) {
- *error = QQmlCompileError(alias->referenceLocation, tr("Invalid alias target location: %1").arg(property.toString()));
- break;
- }
-
- QmlIR::PropertyResolver resolver(targetCache);
-
- QQmlPropertyData *targetProperty = resolver.property(property.toString());
-
- // If it's an alias that we haven't resolved yet, try again later.
- if (!targetProperty) {
- bool aliasPointsToOtherAlias = false;
- int localAliasIndex = 0;
- for (auto targetAlias = targetObject->aliasesBegin(), end = targetObject->aliasesEnd(); targetAlias != end; ++targetAlias, ++localAliasIndex) {
- if (stringAt(targetAlias->nameIndex) == property) {
- aliasPointsToOtherAlias = true;
- break;
- }
- }
- if (aliasPointsToOtherAlias) {
- if (targetObjectIndex == objectIndex) {
- alias->localAliasIndex = localAliasIndex;
- alias->aliasToLocalAlias = true;
- alias->flags |= QV4::CompiledData::Alias::Resolved;
- ++numResolvedAliases;
- continue;
- }
-
- // restore
- alias->idIndex = idIndex;
- // Try again later and resolve the target alias first.
- break;
- }
- }
-
- if (!targetProperty || targetProperty->coreIndex() > 0x0000FFFF) {
- *error = QQmlCompileError(alias->referenceLocation, tr("Invalid alias target location: %1").arg(property.toString()));
- break;
- }
-
- propIdx = QQmlPropertyIndex(targetProperty->coreIndex());
-
- if (!subProperty.isEmpty()) {
- const QMetaObject *valueTypeMetaObject = QQmlValueTypeFactory::metaObjectForMetaType(targetProperty->propType());
- if (!valueTypeMetaObject) {
- *error = QQmlCompileError(alias->referenceLocation, tr("Invalid alias target location: %1").arg(subProperty.toString()));
- break;
- }
-
- int valueTypeIndex =
- valueTypeMetaObject->indexOfProperty(subProperty.toString().toUtf8().constData());
- if (valueTypeIndex == -1) {
- *error = QQmlCompileError(alias->referenceLocation, tr("Invalid alias target location: %1").arg(subProperty.toString()));
- break;
- }
- Q_ASSERT(valueTypeIndex <= 0x0000FFFF);
-
- propIdx = QQmlPropertyIndex(propIdx.coreIndex(), valueTypeIndex);
- } else {
- if (targetProperty->isQObject())
- alias->flags |= QV4::CompiledData::Alias::AliasPointsToPointerObject;
- }
- }
-
- alias->encodedMetaPropertyIndex = propIdx.toEncoded();
- alias->flags |= QV4::CompiledData::Alias::Resolved;
- numResolvedAliases++;
- }
-
- if (numResolvedAliases == 0)
- return seenUnresolvedAlias ? NoAliasResolved : AllAliasesResolved;
-
- return SomeAliasesResolved;
-}
-
-QQmlDeferredAndCustomParserBindingScanner::QQmlDeferredAndCustomParserBindingScanner(QQmlTypeCompiler *typeCompiler)
- : QQmlCompilePass(typeCompiler)
- , qmlObjects(typeCompiler->qmlObjects())
- , propertyCaches(typeCompiler->propertyCaches())
- , customParsers(typeCompiler->customParserCache())
- , _seenObjectWithId(false)
-{
-}
-
-bool QQmlDeferredAndCustomParserBindingScanner::scanObject()
-{
- return scanObject(/*root object*/0);
-}
-
-bool QQmlDeferredAndCustomParserBindingScanner::scanObject(int objectIndex)
-{
- QmlIR::Object *obj = qmlObjects->at(objectIndex);
- if (obj->idNameIndex != 0)
- _seenObjectWithId = true;
-
- if (obj->flags & QV4::CompiledData::Object::IsComponent) {
- Q_ASSERT(obj->bindingCount() == 1);
- const QV4::CompiledData::Binding *componentBinding = obj->firstBinding();
- Q_ASSERT(componentBinding->type == QV4::CompiledData::Binding::Type_Object);
- return scanObject(componentBinding->value.objectIndex);
- }
-
- QQmlPropertyCache *propertyCache = propertyCaches->at(objectIndex);
- if (!propertyCache)
- return true;
-
- QString defaultPropertyName;
- QQmlPropertyData *defaultProperty = nullptr;
- if (obj->indexOfDefaultPropertyOrAlias != -1) {
- QQmlPropertyCache *cache = propertyCache->parent();
- defaultPropertyName = cache->defaultPropertyName();
- defaultProperty = cache->defaultProperty();
- } else {
- defaultPropertyName = propertyCache->defaultPropertyName();
- defaultProperty = propertyCache->defaultProperty();
- }
-
- QQmlCustomParser *customParser = customParsers.value(obj->inheritedTypeNameIndex);
-
- QmlIR::PropertyResolver propertyResolver(propertyCache);
-
- QStringList deferredPropertyNames;
- {
- const QMetaObject *mo = propertyCache->firstCppMetaObject();
- const int namesIndex = mo->indexOfClassInfo("DeferredPropertyNames");
- if (namesIndex != -1) {
- QMetaClassInfo classInfo = mo->classInfo(namesIndex);
- deferredPropertyNames = QString::fromUtf8(classInfo.value()).split(QLatin1Char(','));
- }
- }
-
- for (QmlIR::Binding *binding = obj->firstBinding(); binding; binding = binding->next) {
- QQmlPropertyData *pd = nullptr;
- QString name = stringAt(binding->propertyNameIndex);
-
- if (customParser) {
- if (binding->type == QV4::CompiledData::Binding::Type_AttachedProperty) {
- if (customParser->flags() & QQmlCustomParser::AcceptsAttachedProperties) {
- binding->flags |= QV4::CompiledData::Binding::IsCustomParserBinding;
- obj->flags |= QV4::CompiledData::Object::HasCustomParserBindings;
- continue;
- }
- } else if (QmlIR::IRBuilder::isSignalPropertyName(name)
- && !(customParser->flags() & QQmlCustomParser::AcceptsSignalHandlers)) {
- obj->flags |= QV4::CompiledData::Object::HasCustomParserBindings;
- binding->flags |= QV4::CompiledData::Binding::IsCustomParserBinding;
- continue;
- }
- }
-
- if (name.isEmpty()) {
- pd = defaultProperty;
- name = defaultPropertyName;
- } else {
- if (name.constData()->isUpper())
- continue;
-
- bool notInRevision = false;
- pd = propertyResolver.property(name, &notInRevision, QmlIR::PropertyResolver::CheckRevision);
- }
-
- bool seenSubObjectWithId = false;
-
- if (binding->type >= QV4::CompiledData::Binding::Type_Object && (pd || binding->isAttachedProperty())) {
- qSwap(_seenObjectWithId, seenSubObjectWithId);
- const bool subObjectValid = scanObject(binding->value.objectIndex);
- qSwap(_seenObjectWithId, seenSubObjectWithId);
- if (!subObjectValid)
- return false;
- _seenObjectWithId |= seenSubObjectWithId;
- }
-
- if (!seenSubObjectWithId && binding->type != QV4::CompiledData::Binding::Type_GroupProperty
- && !deferredPropertyNames.isEmpty() && deferredPropertyNames.contains(name)) {
-
- binding->flags |= QV4::CompiledData::Binding::IsDeferredBinding;
- obj->flags |= QV4::CompiledData::Object::HasDeferredBindings;
- }
-
- if (binding->flags & QV4::CompiledData::Binding::IsSignalHandlerExpression
- || binding->flags & QV4::CompiledData::Binding::IsSignalHandlerObject)
- continue;
-
- if (!pd) {
- if (customParser) {
- obj->flags |= QV4::CompiledData::Object::HasCustomParserBindings;
- binding->flags |= QV4::CompiledData::Binding::IsCustomParserBinding;
- }
- }
- }
-
- return true;
-}
-
-QQmlJSCodeGenerator::QQmlJSCodeGenerator(QQmlTypeCompiler *typeCompiler, QmlIR::JSCodeGen *v4CodeGen)
- : QQmlCompilePass(typeCompiler)
- , customParsers(typeCompiler->customParserCache())
- , qmlObjects(*typeCompiler->qmlObjects())
- , propertyCaches(typeCompiler->propertyCaches())
- , v4CodeGen(v4CodeGen)
-{
-}
-
-bool QQmlJSCodeGenerator::generateCodeForComponents()
-{
- const QVector<quint32> &componentRoots = compiler->componentRoots();
- for (int i = 0; i < componentRoots.count(); ++i) {
- if (!compileComponent(componentRoots.at(i)))
- return false;
- }
-
- return compileComponent(/*root object*/0);
-}
-
-bool QQmlJSCodeGenerator::compileComponent(int contextObject)
-{
- const QmlIR::Object *obj = qmlObjects.at(contextObject);
- if (obj->flags & QV4::CompiledData::Object::IsComponent) {
- Q_ASSERT(obj->bindingCount() == 1);
- const QV4::CompiledData::Binding *componentBinding = obj->firstBinding();
- Q_ASSERT(componentBinding->type == QV4::CompiledData::Binding::Type_Object);
- contextObject = componentBinding->value.objectIndex;
- }
-
- if (!compileJavaScriptCodeInObjectsRecursively(contextObject, contextObject))
- return false;
-
- return true;
-}
-
-bool QQmlJSCodeGenerator::compileJavaScriptCodeInObjectsRecursively(int objectIndex, int scopeObjectIndex)
-{
- QmlIR::Object *object = qmlObjects.at(objectIndex);
- if (object->flags & QV4::CompiledData::Object::IsComponent)
- return true;
-
- if (object->functionsAndExpressions->count > 0) {
- QList<QmlIR::CompiledFunctionOrExpression> functionsToCompile;
- for (QmlIR::CompiledFunctionOrExpression *foe = object->functionsAndExpressions->first; foe; foe = foe->next)
- functionsToCompile << *foe;
- const QVector<int> runtimeFunctionIndices = v4CodeGen->generateJSCodeForFunctionsAndBindings(functionsToCompile);
- const QList<QQmlError> jsErrors = v4CodeGen->qmlErrors();
- if (!jsErrors.isEmpty()) {
- for (const QQmlError &e : jsErrors)
- compiler->recordError(e);
- return false;
- }
-
- QQmlJS::MemoryPool *pool = compiler->memoryPool();
- object->runtimeFunctionIndices.allocate(pool, runtimeFunctionIndices);
- }
-
- for (const QmlIR::Binding *binding = object->firstBinding(); binding; binding = binding->next) {
- if (binding->type < QV4::CompiledData::Binding::Type_Object)
- continue;
-
- int target = binding->value.objectIndex;
- int scope = binding->type == QV4::CompiledData::Binding::Type_Object ? target : scopeObjectIndex;
-
- if (!compileJavaScriptCodeInObjectsRecursively(binding->value.objectIndex, scope))
- return false;
- }
-
- return true;
-}
-
-QQmlDefaultPropertyMerger::QQmlDefaultPropertyMerger(QQmlTypeCompiler *typeCompiler)
- : QQmlCompilePass(typeCompiler)
- , qmlObjects(*typeCompiler->qmlObjects())
- , propertyCaches(typeCompiler->propertyCaches())
-{
-
-}
-
-void QQmlDefaultPropertyMerger::mergeDefaultProperties()
-{
- for (int i = 0; i < qmlObjects.count(); ++i)
- mergeDefaultProperties(i);
-}
-
-void QQmlDefaultPropertyMerger::mergeDefaultProperties(int objectIndex)
-{
- QQmlPropertyCache *propertyCache = propertyCaches->at(objectIndex);
- if (!propertyCache)
- return;
-
- QmlIR::Object *object = qmlObjects.at(objectIndex);
-
- QString defaultProperty = object->indexOfDefaultPropertyOrAlias != -1 ? propertyCache->parent()->defaultPropertyName() : propertyCache->defaultPropertyName();
- QmlIR::Binding *bindingsToReinsert = nullptr;
- QmlIR::Binding *tail = nullptr;
-
- QmlIR::Binding *previousBinding = nullptr;
- QmlIR::Binding *binding = object->firstBinding();
- while (binding) {
- if (binding->propertyNameIndex == quint32(0) || stringAt(binding->propertyNameIndex) != defaultProperty) {
- previousBinding = binding;
- binding = binding->next;
- continue;
- }
-
- QmlIR::Binding *toReinsert = binding;
- binding = object->unlinkBinding(previousBinding, binding);
-
- if (!tail) {
- bindingsToReinsert = toReinsert;
- tail = toReinsert;
- } else {
- tail->next = toReinsert;
- tail = tail->next;
- }
- tail->next = nullptr;
- }
-
- binding = bindingsToReinsert;
- while (binding) {
- QmlIR::Binding *toReinsert = binding;
- binding = binding->next;
- object->insertSorted(toReinsert);
- }
-}
-
-QT_END_NAMESPACE
diff --git a/src/qml/compiler/qqmltypecompiler_p.h b/src/qml/compiler/qqmltypecompiler_p.h
deleted file mode 100644
index a49b97453f..0000000000
--- a/src/qml/compiler/qqmltypecompiler_p.h
+++ /dev/null
@@ -1,348 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the tools applications 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 QQMLTYPECOMPILER_P_H
-#define QQMLTYPECOMPILER_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 <qglobal.h>
-#include <qqmlerror.h>
-#include <qhash.h>
-#include <private/qqmltypeloader_p.h>
-#include <private/qqmlirbuilder_p.h>
-#include <private/qqmlpropertycachecreator_p.h>
-
-QT_BEGIN_NAMESPACE
-
-class QQmlEnginePrivate;
-class QQmlError;
-class QQmlTypeData;
-class QQmlImports;
-
-namespace QmlIR {
-struct Document;
-}
-
-namespace QV4 {
-namespace CompiledData {
-struct QmlUnit;
-struct Location;
-}
-}
-
-struct QQmlTypeCompiler
-{
- Q_DECLARE_TR_FUNCTIONS(QQmlTypeCompiler)
-public:
- QQmlTypeCompiler(QQmlEnginePrivate *engine, QQmlTypeData *typeData, QmlIR::Document *document,
- const QQmlRefPointer<QQmlTypeNameCache> &typeNameCache,
- QV4::CompiledData::ResolvedTypeReferenceMap *resolvedTypeCache,
- const QV4::CompiledData::DependentTypesHasher &dependencyHasher);
-
- // --- interface used by QQmlPropertyCacheCreator
- typedef QmlIR::Object CompiledObject;
- const QmlIR::Object *objectAt(int index) const { return document->objects.at(index); }
- int objectCount() const { return document->objects.count(); }
- QString stringAt(int idx) const;
- QmlIR::PoolList<QmlIR::Function>::Iterator objectFunctionsBegin(const QmlIR::Object *object) const { return object->functionsBegin(); }
- QmlIR::PoolList<QmlIR::Function>::Iterator objectFunctionsEnd(const QmlIR::Object *object) const { return object->functionsEnd(); }
- QV4::CompiledData::ResolvedTypeReferenceMap *resolvedTypes = nullptr;
- // ---
-
- QQmlRefPointer<QV4::CompiledData::CompilationUnit> compile();
-
- QList<QQmlError> compilationErrors() const { return errors; }
- void recordError(QQmlError error);
- void recordError(const QV4::CompiledData::Location &location, const QString &description);
- void recordError(const QQmlCompileError &error);
-
- int registerString(const QString &str);
- int registerConstant(QV4::ReturnedValue v);
-
- const QV4::CompiledData::Unit *qmlUnit() const;
-
- QUrl url() const { return typeData->finalUrl(); }
- QQmlEnginePrivate *enginePrivate() const { return engine; }
- const QQmlImports *imports() const;
- QVector<QmlIR::Object *> *qmlObjects() const;
- void setPropertyCaches(QQmlPropertyCacheVector &&caches);
- const QQmlPropertyCacheVector *propertyCaches() const;
- QQmlPropertyCacheVector &&takePropertyCaches();
- void setComponentRoots(const QVector<quint32> &roots) { m_componentRoots = roots; }
- const QVector<quint32> &componentRoots() const { return m_componentRoots; }
- QQmlJS::MemoryPool *memoryPool();
- QStringRef newStringRef(const QString &string);
- const QV4::Compiler::StringTableGenerator *stringPool() const;
- void setBindingPropertyDataPerObject(const QVector<QV4::CompiledData::BindingPropertyData> &propertyData);
-
- const QHash<int, QQmlCustomParser*> &customParserCache() const { return customParsers; }
-
- QString bindingAsString(const QmlIR::Object *object, int scriptIndex) const;
-
- void addImport(const QString &module, const QString &qualifier, int majorVersion, int minorVersion);
-
- QV4::CompiledData::ResolvedTypeReference *resolvedType(int id) const
- {
- return resolvedTypes->value(id);
- }
-
-private:
- QList<QQmlError> errors;
- QQmlEnginePrivate *engine;
- QQmlTypeData *typeData;
- const QV4::CompiledData::DependentTypesHasher &dependencyHasher;
- QQmlRefPointer<QQmlTypeNameCache> typeNameCache;
- QmlIR::Document *document;
- // index is string index of type name (use obj->inheritedTypeNameIndex)
- QHash<int, QQmlCustomParser*> customParsers;
-
- // index in first hash is component index, vector inside contains object indices of objects with id property
- QVector<quint32> m_componentRoots;
- QQmlPropertyCacheVector m_propertyCaches;
-};
-
-struct QQmlCompilePass
-{
- QQmlCompilePass(QQmlTypeCompiler *typeCompiler);
-
- QString stringAt(int idx) const { return compiler->stringAt(idx); }
-protected:
- void recordError(const QV4::CompiledData::Location &location, const QString &description) const
- { compiler->recordError(location, description); }
- void recordError(const QQmlCompileError &error)
- { compiler->recordError(error); }
-
- QV4::CompiledData::ResolvedTypeReference *resolvedType(int id) const
- { return compiler->resolvedType(id); }
- bool containsResolvedType(int id) const
- { return compiler->resolvedTypes->contains(id); }
- QV4::CompiledData::ResolvedTypeReferenceMap::iterator insertResolvedType(
- int id, QV4::CompiledData::ResolvedTypeReference *value)
- { return compiler->resolvedTypes->insert(id, value); }
-
- QQmlTypeCompiler *compiler;
-};
-
-// "Converts" signal expressions to full-fleged function declarations with
-// parameters taken from the signal declarations
-// It also updates the QV4::CompiledData::Binding objects to set the property name
-// to the final signal name (onTextChanged -> textChanged) and sets the IsSignalExpression flag.
-struct SignalHandlerConverter : public QQmlCompilePass
-{
- Q_DECLARE_TR_FUNCTIONS(SignalHandlerConverter)
-public:
- SignalHandlerConverter(QQmlTypeCompiler *typeCompiler);
-
- bool convertSignalHandlerExpressionsToFunctionDeclarations();
-
-private:
- bool convertSignalHandlerExpressionsToFunctionDeclarations(const QmlIR::Object *obj, const QString &typeName, QQmlPropertyCache *propertyCache);
-
- QQmlEnginePrivate *enginePrivate;
- const QVector<QmlIR::Object*> &qmlObjects;
- const QQmlImports *imports;
- const QHash<int, QQmlCustomParser*> &customParsers;
- const QSet<QString> &illegalNames;
- const QQmlPropertyCacheVector * const propertyCaches;
-};
-
-// ### This will go away when the codegen resolves all enums to constant expressions
-// and we replace the constant expression with a literal binding instead of using
-// a script.
-class QQmlEnumTypeResolver : public QQmlCompilePass
-{
- Q_DECLARE_TR_FUNCTIONS(QQmlEnumTypeResolver)
-public:
- QQmlEnumTypeResolver(QQmlTypeCompiler *typeCompiler);
-
- bool resolveEnumBindings();
-
-private:
- bool assignEnumToBinding(QmlIR::Binding *binding, const QStringRef &enumName, int enumValue, bool isQtObject);
- bool assignEnumToBinding(QmlIR::Binding *binding, const QString &enumName, int enumValue, bool isQtObject)
- {
- return assignEnumToBinding(binding, QStringRef(&enumName), enumValue, isQtObject);
- }
- bool tryQualifiedEnumAssignment(const QmlIR::Object *obj, const QQmlPropertyCache *propertyCache,
- const QQmlPropertyData *prop,
- QmlIR::Binding *binding);
- int evaluateEnum(const QString &scope, const QStringRef &enumName, const QStringRef &enumValue, bool *ok) const;
-
-
- const QVector<QmlIR::Object*> &qmlObjects;
- const QQmlPropertyCacheVector * const propertyCaches;
- const QQmlImports *imports;
-};
-
-class QQmlCustomParserScriptIndexer: public QQmlCompilePass
-{
-public:
- QQmlCustomParserScriptIndexer(QQmlTypeCompiler *typeCompiler);
-
- void annotateBindingsWithScriptStrings();
-
-private:
- void scanObjectRecursively(int objectIndex, bool annotateScriptBindings = false);
-
- const QVector<QmlIR::Object*> &qmlObjects;
- const QHash<int, QQmlCustomParser*> &customParsers;
-};
-
-// Annotate properties bound to aliases with a flag
-class QQmlAliasAnnotator : public QQmlCompilePass
-{
-public:
- QQmlAliasAnnotator(QQmlTypeCompiler *typeCompiler);
-
- void annotateBindingsToAliases();
-private:
- const QVector<QmlIR::Object*> &qmlObjects;
- const QQmlPropertyCacheVector * const propertyCaches;
-};
-
-class QQmlScriptStringScanner : public QQmlCompilePass
-{
-public:
- QQmlScriptStringScanner(QQmlTypeCompiler *typeCompiler);
-
- void scan();
-
-private:
- const QVector<QmlIR::Object*> &qmlObjects;
- const QQmlPropertyCacheVector * const propertyCaches;
-};
-
-class QQmlComponentAndAliasResolver : public QQmlCompilePass
-{
- Q_DECLARE_TR_FUNCTIONS(QQmlAnonymousComponentResolver)
-public:
- QQmlComponentAndAliasResolver(QQmlTypeCompiler *typeCompiler);
-
- bool resolve();
-
-protected:
- void findAndRegisterImplicitComponents(const QmlIR::Object *obj, QQmlPropertyCache *propertyCache);
- bool collectIdsAndAliases(int objectIndex);
- bool resolveAliases(int componentIndex);
- void propertyDataForAlias(QmlIR::Alias *alias, int *type, quint32 *propertyFlags);
-
- enum AliasResolutionResult {
- NoAliasResolved,
- SomeAliasesResolved,
- AllAliasesResolved
- };
-
- AliasResolutionResult resolveAliasesInObject(int objectIndex, QQmlCompileError *error);
-
- QQmlEnginePrivate *enginePrivate;
- QQmlJS::MemoryPool *pool;
-
- QVector<QmlIR::Object*> *qmlObjects;
-
- // indices of the objects that are actually Component {}
- QVector<quint32> componentRoots;
-
- // Deliberate choice of map over hash here to ensure stable generated output.
- QMap<int, int> _idToObjectIndex;
- QVector<int> _objectsWithAliases;
-
- QQmlPropertyCacheVector propertyCaches;
-};
-
-class QQmlDeferredAndCustomParserBindingScanner : public QQmlCompilePass
-{
-public:
- QQmlDeferredAndCustomParserBindingScanner(QQmlTypeCompiler *typeCompiler);
-
- bool scanObject();
-
-private:
- bool scanObject(int objectIndex);
-
- QVector<QmlIR::Object*> *qmlObjects;
- const QQmlPropertyCacheVector * const propertyCaches;
- const QHash<int, QQmlCustomParser*> &customParsers;
-
- bool _seenObjectWithId;
-};
-
-// ### merge with QtQml::JSCodeGen and operate directly on object->functionsAndExpressions once old compiler is gone.
-class QQmlJSCodeGenerator : public QQmlCompilePass
-{
-public:
- QQmlJSCodeGenerator(QQmlTypeCompiler *typeCompiler, QmlIR::JSCodeGen *v4CodeGen);
-
- bool generateCodeForComponents();
-
-private:
- bool compileComponent(int componentRoot);
- bool compileJavaScriptCodeInObjectsRecursively(int objectIndex, int scopeObjectIndex);
-
- const QHash<int, QQmlCustomParser*> &customParsers;
- const QVector<QmlIR::Object*> &qmlObjects;
- const QQmlPropertyCacheVector * const propertyCaches;
- QmlIR::JSCodeGen * const v4CodeGen;
-};
-
-class QQmlDefaultPropertyMerger : public QQmlCompilePass
-{
-public:
- QQmlDefaultPropertyMerger(QQmlTypeCompiler *typeCompiler);
-
- void mergeDefaultProperties();
-
-private:
- void mergeDefaultProperties(int objectIndex);
-
- const QVector<QmlIR::Object*> &qmlObjects;
- const QQmlPropertyCacheVector * const propertyCaches;
-};
-
-QT_END_NAMESPACE
-
-#endif // QQMLTYPECOMPILER_P_H
diff --git a/src/qml/compiler/qv4bytecodegenerator.cpp b/src/qml/compiler/qv4bytecodegenerator.cpp
index ea252a6013..7df1614ffe 100644
--- a/src/qml/compiler/qv4bytecodegenerator.cpp
+++ b/src/qml/compiler/qv4bytecodegenerator.cpp
@@ -206,7 +206,6 @@ int BytecodeGenerator::addInstructionHelper(Instr::Type type, const Instr &i, in
lastInstrType = int(type);
lastInstr = i;
-#if QT_CONFIG(qml_debug)
if (debugMode && type != Instr::Type::Debug) {
QT_WARNING_PUSH
QT_WARNING_DISABLE_GCC("-Wmaybe-uninitialized") // broken gcc warns about Instruction::Debug()
@@ -219,9 +218,6 @@ QT_WARNING_DISABLE_GCC("-Wmaybe-uninitialized") // broken gcc warns about Instru
}
QT_WARNING_POP
}
-#else
- Q_UNUSED(debugMode);
-#endif
const int pos = instructions.size();
diff --git a/src/qml/compiler/qv4bytecodegenerator_p.h b/src/qml/compiler/qv4bytecodegenerator_p.h
index 1d0a57c536..8c509dd9f1 100644
--- a/src/qml/compiler/qv4bytecodegenerator_p.h
+++ b/src/qml/compiler/qv4bytecodegenerator_p.h
@@ -62,12 +62,15 @@ class SourceLocation;
}
namespace QV4 {
+
+namespace Compiler {
+struct Context;
+}
+
namespace Moth {
class BytecodeGenerator {
public:
- typedef CompiledData::Function::TraceInfoCount TraceInfoCount;
-
BytecodeGenerator(int line, bool debug)
: startLine(line), debugMode(debug) {}
@@ -164,15 +167,6 @@ public:
addInstructionHelper(Moth::Instr::Type(InstrT), genericInstr);
}
- // Same as addInstruction, but also add a trace slot. Move only, because the instruction cannot
- // be reused afterwards.
- template<int InstrT>
- void addTracingInstruction(InstrData<InstrT> data)
- {
- data.traceSlot = nextTraceInfo();
- addInstruction(data);
- }
-
Q_REQUIRED_RESULT Jump jump()
{
QT_WARNING_PUSH
@@ -184,12 +178,12 @@ QT_WARNING_POP
Q_REQUIRED_RESULT Jump jumpTrue()
{
- return addTracingJumpInstruction(Instruction::JumpTrue());
+ return addJumpInstruction(Instruction::JumpTrue());
}
Q_REQUIRED_RESULT Jump jumpFalse()
{
- return addTracingJumpInstruction(Instruction::JumpFalse());
+ return addJumpInstruction(Instruction::JumpFalse());
}
Q_REQUIRED_RESULT Jump jumpNotUndefined()
@@ -209,7 +203,7 @@ QT_WARNING_POP
Instruction::CmpStrictEqual cmp;
cmp.lhs = lhs;
addInstruction(std::move(cmp));
- addTracingJumpInstruction(Instruction::JumpTrue()).link(target);
+ addJumpInstruction(Instruction::JumpTrue()).link(target);
}
void jumpStrictNotEqual(const StackSlot &lhs, const Label &target)
@@ -217,7 +211,13 @@ QT_WARNING_POP
Instruction::CmpStrictNotEqual cmp;
cmp.lhs = lhs;
addInstruction(std::move(cmp));
- addTracingJumpInstruction(Instruction::JumpTrue()).link(target);
+ addJumpInstruction(Instruction::JumpTrue()).link(target);
+ }
+
+ void checkException()
+ {
+ Instruction::CheckException chk;
+ addInstruction(chk);
}
void setUnwindHandler(ExceptionHandler *handler)
@@ -258,13 +258,6 @@ QT_WARNING_POP
void finalize(Compiler::Context *context);
template<int InstrT>
- Jump addTracingJumpInstruction(InstrData<InstrT> &&data)
- {
- data.traceSlot = nextTraceInfo();
- return addJumpInstruction(data);
- }
-
- template<int InstrT>
Jump addJumpInstruction(const InstrData<InstrT> &data)
{
Instr genericInstr;
@@ -275,9 +268,9 @@ QT_WARNING_POP
void addCJumpInstruction(bool jumpOnFalse, const Label *trueLabel, const Label *falseLabel)
{
if (jumpOnFalse)
- addTracingJumpInstruction(Instruction::JumpFalse()).link(*falseLabel);
+ addJumpInstruction(Instruction::JumpFalse()).link(*falseLabel);
else
- addTracingJumpInstruction(Instruction::JumpTrue()).link(*trueLabel);
+ addJumpInstruction(Instruction::JumpTrue()).link(*trueLabel);
}
void clearLastInstruction()
@@ -285,27 +278,6 @@ QT_WARNING_POP
lastInstrType = -1;
}
- TraceInfoCount nextTraceInfo()
- {
- // If tracing is disabled, use slot 0 to unconditionally store all trace info
- if (nTraceInfos == CompiledData::Function::NoTracing())
- return TraceInfoCount(0);
- return nTraceInfos++;
- }
-
- void setTracing(bool onoff, int argumentCount)
- {
- if (onoff)
- nTraceInfos = argumentCount;
- else
- nTraceInfos = CompiledData::Function::NoTracing();
- }
-
- TraceInfoCount traceInfoCount() const
- {
- return nTraceInfos;
- }
-
void addLoopStart(const Label &start)
{
_labelInfos.push_back({ start.index });
@@ -346,8 +318,6 @@ private:
int lastInstrType = -1;
Moth::Instr lastInstr;
- TraceInfoCount nTraceInfos = TraceInfoCount(0);
-
struct LabelInfo {
int labelIndex;
};
diff --git a/src/qml/compiler/qv4bytecodehandler.cpp b/src/qml/compiler/qv4bytecodehandler.cpp
index 92b112c2fa..f9f755b8c0 100644
--- a/src/qml/compiler/qv4bytecodehandler.cpp
+++ b/src/qml/compiler/qv4bytecodehandler.cpp
@@ -58,9 +58,10 @@ ByteCodeHandler::~ByteCodeHandler()
Q_UNUSED(base_ptr); \
_currentOffset = _nextOffset; \
_nextOffset = code - start; \
- startInstruction(Instr::Type::instr); \
- INSTR_##instr(DISPATCH) \
- endInstruction(Instr::Type::instr); \
+ if (startInstruction(Instr::Type::instr) == ProcessInstruction) { \
+ INSTR_##instr(DISPATCH) \
+ endInstruction(Instr::Type::instr); \
+ } \
continue; \
}
diff --git a/src/qml/compiler/qv4bytecodehandler_p.h b/src/qml/compiler/qv4bytecodehandler_p.h
index 797d25b8d0..f1e7c99447 100644
--- a/src/qml/compiler/qv4bytecodehandler_p.h
+++ b/src/qml/compiler/qv4bytecodehandler_p.h
@@ -105,7 +105,8 @@ public:
protected:
FOR_EACH_MOTH_INSTR(BYTECODE_HANDLER_DEFINE_VIRTUAL_BYTECODE_HANDLER)
- virtual void startInstruction(Moth::Instr::Type instr) = 0;
+ enum Verdict { ProcessInstruction, SkipInstruction };
+ virtual Verdict startInstruction(Moth::Instr::Type instr) = 0;
virtual void endInstruction(Moth::Instr::Type instr) = 0;
private:
diff --git a/src/qml/compiler/qv4codegen.cpp b/src/qml/compiler/qv4codegen.cpp
index 5acc64bd81..c43ea64e2e 100644
--- a/src/qml/compiler/qv4codegen.cpp
+++ b/src/qml/compiler/qv4codegen.cpp
@@ -43,18 +43,18 @@
#include <QtCore/QCoreApplication>
#include <QtCore/QStringList>
#include <QtCore/QStack>
+#include <QtCore/qurl.h>
#include <QScopeGuard>
#include <private/qqmljsast_p.h>
-#include <private/qv4string_p.h>
-#include <private/qv4value_p.h>
+#include <private/qqmljslexer_p.h>
+#include <private/qqmljsparser_p.h>
+#include <private/qv4staticvalue_p.h>
#include <private/qv4compilercontext_p.h>
#include <private/qv4compilercontrolflow_p.h>
#include <private/qv4bytecodegenerator_p.h>
#include <private/qv4compilerscanfunctions_p.h>
-
-#ifndef V4_BOOTSTRAP
-# include <qqmlerror.h>
-#endif
+#include <private/qv4stringtoarrayindex_p.h>
+#include <private/qqmljsdiagnosticmessage_p.h>
#include <cmath>
#include <iostream>
@@ -68,6 +68,7 @@ static const bool disable_lookups = false;
QT_USE_NAMESPACE
using namespace QV4;
using namespace QV4::Compiler;
+using namespace QQmlJS;
using namespace QQmlJS::AST;
static inline void setJumpOutLocation(QV4::Moth::BytecodeGenerator *bytecodeGenerator,
@@ -97,7 +98,6 @@ Codegen::Codegen(QV4::Compiler::JSUnitGenerator *jsUnitGenerator, bool strict)
, jsUnitGenerator(jsUnitGenerator)
, _strictMode(strict)
, _fileNameIsUrl(false)
- , hasError(false)
{
jsUnitGenerator->codeGeneratorName = QStringLiteral("moth");
pushExpr();
@@ -190,7 +190,7 @@ void Codegen::generateFromProgram(const QString &fileName,
ScanFunctions scan(this, sourceCode, contextType);
scan(node);
- if (hasError)
+ if (hasError())
return;
defineFunction(QStringLiteral("%entry"), node, nullptr, node->statements);
@@ -214,7 +214,7 @@ void Codegen::generateFromModule(const QString &fileName,
ScanFunctions scan(this, sourceCode, ContextType::ESModule);
scan(node);
- if (hasError)
+ if (hasError())
return;
{
@@ -264,17 +264,30 @@ Context *Codegen::enterBlock(Node *node)
Codegen::Reference Codegen::unop(UnaryOperation op, const Reference &expr)
{
- if (hasError)
+ if (hasError())
return exprResult();
if (expr.isConstant()) {
- auto v = Value::fromReturnedValue(expr.constant);
+ auto v = StaticValue::fromReturnedValue(expr.constant);
if (v.isNumber()) {
switch (op) {
case Not:
return Reference::fromConst(this, Encode(!v.toBoolean()));
case UMinus:
- return Reference::fromConst(this, Runtime::method_uMinus(v));
+ // This duplicates some of the logic from Runtime::UMinus::call()
+ ReturnedValue r;
+ if (v.isInteger()) {
+ int intVal = v.integerValue();
+ if (intVal && intVal != std::numeric_limits<int>::min())
+ r = QV4::Encode(-intVal);
+ else
+ r = QV4::Encode(-double(intVal));
+ } else if (v.isDouble()) {
+ r = QV4::Encode(-v.doubleValue());
+ } else {
+ r = QV4::Encode(-v.int_32());
+ }
+ return Reference::fromConst(this, r);
case UPlus:
return expr;
case Compl:
@@ -289,12 +302,12 @@ Codegen::Reference Codegen::unop(UnaryOperation op, const Reference &expr)
case UMinus: {
expr.loadInAccumulator();
Instruction::UMinus uminus = {};
- bytecodeGenerator->addTracingInstruction(uminus);
+ bytecodeGenerator->addInstruction(uminus);
return Reference::fromAccumulator(this);
}
case UPlus: {
expr.loadInAccumulator();
- Instruction::UPlus uplus;
+ Instruction::UPlus uplus = {};
bytecodeGenerator->addInstruction(uplus);
return Reference::fromAccumulator(this);
}
@@ -314,11 +327,11 @@ Codegen::Reference Codegen::unop(UnaryOperation op, const Reference &expr)
if (!exprAccept(nx) || requiresReturnValue) {
Reference e = expr.asLValue();
e.loadInAccumulator();
- Instruction::UPlus uplus;
+ Instruction::UPlus uplus = {};
bytecodeGenerator->addInstruction(uplus);
Reference originalValue = Reference::fromStackSlot(this).storeRetainAccumulator();
Instruction::Increment inc = {};
- bytecodeGenerator->addTracingInstruction(inc);
+ bytecodeGenerator->addInstruction(inc);
e.storeConsumeAccumulator();
return originalValue;
} else {
@@ -330,7 +343,7 @@ Codegen::Reference Codegen::unop(UnaryOperation op, const Reference &expr)
Reference e = expr.asLValue();
e.loadInAccumulator();
Instruction::Increment inc = {};
- bytecodeGenerator->addTracingInstruction(inc);
+ bytecodeGenerator->addInstruction(inc);
if (exprAccept(nx))
return e.storeConsumeAccumulator();
else
@@ -340,11 +353,11 @@ Codegen::Reference Codegen::unop(UnaryOperation op, const Reference &expr)
if (!exprAccept(nx) || requiresReturnValue) {
Reference e = expr.asLValue();
e.loadInAccumulator();
- Instruction::UPlus uplus;
+ Instruction::UPlus uplus = {};
bytecodeGenerator->addInstruction(uplus);
Reference originalValue = Reference::fromStackSlot(this).storeRetainAccumulator();
Instruction::Decrement dec = {};
- bytecodeGenerator->addTracingInstruction(dec);
+ bytecodeGenerator->addInstruction(dec);
e.storeConsumeAccumulator();
return originalValue;
} else {
@@ -356,7 +369,7 @@ Codegen::Reference Codegen::unop(UnaryOperation op, const Reference &expr)
Reference e = expr.asLValue();
e.loadInAccumulator();
Instruction::Decrement dec = {};
- bytecodeGenerator->addTracingInstruction(dec);
+ bytecodeGenerator->addInstruction(dec);
if (exprAccept(nx))
return e.storeConsumeAccumulator();
else
@@ -402,7 +415,7 @@ void Codegen::statement(ExpressionNode *ast)
qSwap(_volatileMemoryLocations, vLocs);
Reference result = popResult();
- if (hasError)
+ if (hasError())
return;
if (result.loadTriggersSideEffect())
result.loadInAccumulator(); // triggers side effects
@@ -412,7 +425,7 @@ void Codegen::statement(ExpressionNode *ast)
void Codegen::condition(ExpressionNode *ast, const BytecodeGenerator::Label *iftrue,
const BytecodeGenerator::Label *iffalse, bool trueBlockFollowsCondition)
{
- if (hasError)
+ if (hasError())
return;
if (!ast)
@@ -422,7 +435,7 @@ void Codegen::condition(ExpressionNode *ast, const BytecodeGenerator::Label *ift
accept(ast);
Result r = popExpr();
- if (hasError)
+ if (hasError())
return;
if (r.format() == ex) {
@@ -576,7 +589,7 @@ Codegen::Reference Codegen::targetForPatternElement(AST::PatternElement *p)
if (!p->bindingTarget || p->destructuringPattern())
return Codegen::Reference::fromStackSlot(this);
Reference lhs = expression(p->bindingTarget);
- if (hasError)
+ if (hasError())
return lhs;
if (!lhs.isLValue()) {
throwReferenceError(p->bindingTarget->firstSourceLocation(), QStringLiteral("Binding target is not a reference."));
@@ -594,14 +607,16 @@ void Codegen::initializeAndDestructureBindingElement(AST::PatternElement *e, con
Reference varToStore = targetForPatternElement(e);
if (isDefinition)
varToStore.isReferenceToConst = false;
- if (hasError)
+ if (hasError())
return;
+ accept(e->typeAnnotation);
+
if (e->initializer) {
if (!baseRef.isValid()) {
// assignment
Reference expr = expression(e->initializer);
- if (hasError)
+ if (hasError())
return;
expr.loadInAccumulator();
varToStore.storeConsumeAccumulator();
@@ -609,7 +624,7 @@ void Codegen::initializeAndDestructureBindingElement(AST::PatternElement *e, con
baseRef.loadInAccumulator();
BytecodeGenerator::Jump jump = bytecodeGenerator->jumpNotUndefined();
Reference expr = expression(e->initializer);
- if (hasError) {
+ if (hasError()) {
jump.link();
return;
}
@@ -620,7 +635,7 @@ void Codegen::initializeAndDestructureBindingElement(AST::PatternElement *e, con
baseRef.loadInAccumulator();
BytecodeGenerator::Jump jump = bytecodeGenerator->jumpNotUndefined();
Reference expr = expression(e->initializer);
- if (hasError) {
+ if (hasError()) {
jump.link();
return;
}
@@ -657,7 +672,7 @@ Codegen::Reference Codegen::referenceForPropertyName(const Codegen::Reference &o
Reference property;
if (cname) {
Reference computedName = expression(cname->expression);
- if (hasError)
+ if (hasError())
return Reference();
computedName = computedName.storeOnStack();
property = Reference::fromSubscript(object, computedName).asLValue();
@@ -680,10 +695,10 @@ void Codegen::destructurePropertyList(const Codegen::Reference &object, PatternP
PatternProperty *p = it->property;
RegisterScope scope(this);
Reference property = referenceForPropertyName(object, p->name);
- if (hasError)
+ if (hasError())
return;
initializeAndDestructureBindingElement(p, property, isDefinition);
- if (hasError)
+ if (hasError())
return;
}
}
@@ -739,7 +754,7 @@ void Codegen::destructureElementList(const Codegen::Reference &array, PatternEle
next.done = iteratorDone.stackSlot();
bytecodeGenerator->addInstruction(next);
initializeAndDestructureBindingElement(e, iteratorValue, isDefinition);
- if (hasError)
+ if (hasError())
return;
}
}
@@ -872,6 +887,12 @@ bool Codegen::visit(ExportDeclaration *ast)
return false;
}
+bool Codegen::visit(TypeAnnotation *ast)
+{
+ throwSyntaxError(ast->firstSourceLocation(), QLatin1String("Type annotations are not supported (yet)."));
+ return false;
+}
+
bool Codegen::visit(StatementList *)
{
Q_UNREACHABLE();
@@ -1003,11 +1024,11 @@ bool Codegen::visit(ClassExpression *ast)
if (ast->heritage) {
bytecodeGenerator->setLocation(ast->heritage->firstSourceLocation());
Reference r = expression(ast->heritage);
- if (hasError)
+ if (hasError())
return false;
r.storeOnStack(heritage.stackSlot());
} else {
- Reference::fromConst(this, Value::emptyValue().asReturnedValue()).loadInAccumulator();
+ Reference::fromConst(this, StaticValue::emptyValue().asReturnedValue()).loadInAccumulator();
heritage.storeConsumeAccumulator();
}
@@ -1022,7 +1043,7 @@ bool Codegen::visit(ClassExpression *ast)
RegisterScope scope(this);
bytecodeGenerator->setLocation(cname->firstSourceLocation());
Reference computedName = expression(cname->expression);
- if (hasError)
+ if (hasError())
return false;
computedName.storeOnStack(member->isStatic ? currentStaticName++ : currentNonStaticName++);
}
@@ -1055,7 +1076,7 @@ bool Codegen::visit(ClassDeclaration *ast)
bool Codegen::visit(Expression *ast)
{
- if (hasError)
+ if (hasError())
return false;
TailCallBlocker blockTailCalls(this);
@@ -1068,7 +1089,7 @@ bool Codegen::visit(Expression *ast)
bool Codegen::visit(ArrayPattern *ast)
{
- if (hasError)
+ if (hasError())
return false;
TailCallBlocker blockTailCalls(this);
@@ -1085,12 +1106,12 @@ bool Codegen::visit(ArrayPattern *ast)
if (args == -1)
args = temp;
if (!arg) {
- auto c = Reference::fromConst(this, Value::emptyValue().asReturnedValue());
+ auto c = Reference::fromConst(this, StaticValue::emptyValue().asReturnedValue());
(void) c.storeOnStack(temp);
} else {
RegisterScope scope(this);
Reference r = expression(arg);
- if (hasError)
+ if (hasError())
return;
(void) r.storeOnStack(temp);
}
@@ -1108,7 +1129,7 @@ bool Codegen::visit(ArrayPattern *ast)
continue;
push(e->initializer);
- if (hasError)
+ if (hasError())
return false;
}
@@ -1140,13 +1161,14 @@ bool Codegen::visit(ArrayPattern *ast)
index.loadInAccumulator();
Instruction::Increment inc = {};
- bytecodeGenerator->addTracingInstruction(inc);
+ bytecodeGenerator->addInstruction(inc);
index.storeConsumeAccumulator();
};
while (it) {
for (Elision *elision = it->elision; elision; elision = elision->next) {
- Reference::fromConst(this, Value::emptyValue().asReturnedValue()).loadInAccumulator();
+ Reference::fromConst(
+ this, StaticValue::emptyValue().asReturnedValue()).loadInAccumulator();
pushAccumulator();
}
@@ -1168,7 +1190,7 @@ bool Codegen::visit(ArrayPattern *ast)
{
RegisterScope innerScope(this);
Reference expr = expression(it->element->initializer);
- if (hasError)
+ if (hasError())
return false;
expr.loadInAccumulator();
@@ -1202,13 +1224,14 @@ bool Codegen::visit(ArrayPattern *ast)
lhsValue.loadInAccumulator();
pushAccumulator();
+ bytecodeGenerator->checkException();
bytecodeGenerator->jump().link(in);
end.link();
}
} else {
RegisterScope innerScope(this);
Reference expr = expression(it->element->initializer);
- if (hasError)
+ if (hasError())
return false;
expr.loadInAccumulator();
@@ -1226,12 +1249,12 @@ bool Codegen::visit(ArrayPattern *ast)
bool Codegen::visit(ArrayMemberExpression *ast)
{
- if (hasError)
+ if (hasError())
return false;
TailCallBlocker blockTailCalls(this);
Reference base = expression(ast->base);
- if (hasError)
+ if (hasError())
return false;
if (base.isSuper()) {
Reference index = expression(ast->expression).storeOnStack();
@@ -1239,11 +1262,11 @@ bool Codegen::visit(ArrayMemberExpression *ast)
return false;
}
base = base.storeOnStack();
- if (hasError)
+ if (hasError())
return false;
if (AST::StringLiteral *str = AST::cast<AST::StringLiteral *>(ast->expression)) {
QString s = str->value.toString();
- uint arrayIndex = QV4::String::toArrayIndex(s);
+ uint arrayIndex = stringToArrayIndex(s);
if (arrayIndex == UINT_MAX) {
setExprResult(Reference::fromMember(base, str->value.toString()));
return false;
@@ -1253,7 +1276,7 @@ bool Codegen::visit(ArrayMemberExpression *ast)
return false;
}
Reference index = expression(ast->expression);
- if (hasError)
+ if (hasError())
return false;
setExprResult(Reference::fromSubscript(base, index));
return false;
@@ -1280,7 +1303,7 @@ static QSOperator::Op baseOp(int op)
bool Codegen::visit(BinaryExpression *ast)
{
- if (hasError)
+ if (hasError())
return false;
TailCallBlocker blockTailCalls(this);
@@ -1298,7 +1321,7 @@ bool Codegen::visit(BinaryExpression *ast)
auto endif = bytecodeGenerator->newLabel();
Reference left = expression(ast->left);
- if (hasError)
+ if (hasError())
return false;
left.loadInAccumulator();
@@ -1308,7 +1331,7 @@ bool Codegen::visit(BinaryExpression *ast)
blockTailCalls.unblock();
Reference right = expression(ast->right);
- if (hasError)
+ if (hasError())
return false;
right.loadInAccumulator();
@@ -1329,7 +1352,7 @@ bool Codegen::visit(BinaryExpression *ast)
auto endif = bytecodeGenerator->newLabel();
Reference left = expression(ast->left);
- if (hasError)
+ if (hasError())
return false;
left.loadInAccumulator();
@@ -1339,7 +1362,7 @@ bool Codegen::visit(BinaryExpression *ast)
blockTailCalls.unblock();
Reference right = expression(ast->right);
- if (hasError)
+ if (hasError())
return false;
right.loadInAccumulator();
@@ -1352,7 +1375,7 @@ bool Codegen::visit(BinaryExpression *ast)
if (AST::Pattern *p = ast->left->patternCast()) {
RegisterScope scope(this);
Reference right = expression(ast->right);
- if (hasError)
+ if (hasError())
return false;
right = right.storeOnStack();
destructurePattern(p, right);
@@ -1363,7 +1386,7 @@ bool Codegen::visit(BinaryExpression *ast)
return false;
}
Reference left = expression(ast->left);
- if (hasError)
+ if (hasError())
return false;
if (!left.isLValue()) {
@@ -1375,7 +1398,7 @@ bool Codegen::visit(BinaryExpression *ast)
return false;
blockTailCalls.unblock();
Reference r = expression(ast->right);
- if (hasError)
+ if (hasError())
return false;
r.loadInAccumulator();
if (exprAccept(nx))
@@ -1386,7 +1409,7 @@ bool Codegen::visit(BinaryExpression *ast)
}
Reference left = expression(ast->left);
- if (hasError)
+ if (hasError())
return false;
switch (ast->op) {
@@ -1420,7 +1443,7 @@ bool Codegen::visit(BinaryExpression *ast)
Reference tempLeft = left.storeOnStack();
Reference right = expression(ast->right);
- if (hasError)
+ if (hasError())
return false;
binopHelper(baseOp(ast->op), tempLeft, right).loadInAccumulator();
@@ -1434,7 +1457,7 @@ bool Codegen::visit(BinaryExpression *ast)
case QSOperator::BitXor:
if (left.isConstant()) {
Reference right = expression(ast->right);
- if (hasError)
+ if (hasError())
return false;
setExprResult(binopHelper(static_cast<QSOperator::Op>(ast->op), right, left));
break;
@@ -1467,7 +1490,7 @@ bool Codegen::visit(BinaryExpression *ast)
left = left.storeOnStack(); // force any loads of the lhs, so the rhs won't clobber it
right = expression(ast->right);
}
- if (hasError)
+ if (hasError())
return false;
setExprResult(binopHelper(static_cast<QSOperator::Op>(ast->op), left, right));
@@ -1488,20 +1511,20 @@ Codegen::Reference Codegen::binopHelper(QSOperator::Op oper, Reference &left, Re
right.loadInAccumulator();
Instruction::Add add;
add.lhs = left.stackSlot();
- bytecodeGenerator->addTracingInstruction(add);
+ bytecodeGenerator->addInstruction(add);
break;
}
case QSOperator::Sub: {
if (right.isConstant() && right.constant == Encode(int(1))) {
left.loadInAccumulator();
Instruction::Decrement dec = {};
- bytecodeGenerator->addTracingInstruction(dec);
+ bytecodeGenerator->addInstruction(dec);
} else {
left = left.storeOnStack();
right.loadInAccumulator();
Instruction::Sub sub;
sub.lhs = left.stackSlot();
- bytecodeGenerator->addTracingInstruction(sub);
+ bytecodeGenerator->addInstruction(sub);
}
break;
}
@@ -1518,7 +1541,7 @@ Codegen::Reference Codegen::binopHelper(QSOperator::Op oper, Reference &left, Re
right.loadInAccumulator();
Instruction::Mul mul;
mul.lhs = left.stackSlot();
- bytecodeGenerator->addTracingInstruction(mul);
+ bytecodeGenerator->addInstruction(mul);
break;
}
case QSOperator::Div: {
@@ -1534,14 +1557,14 @@ Codegen::Reference Codegen::binopHelper(QSOperator::Op oper, Reference &left, Re
right.loadInAccumulator();
Instruction::Mod mod;
mod.lhs = left.stackSlot();
- bytecodeGenerator->addTracingInstruction(mod);
+ bytecodeGenerator->addInstruction(mod);
break;
}
case QSOperator::BitAnd:
if (right.isConstant()) {
- int rightAsInt = Value::fromReturnedValue(right.constant).toInt32();
+ int rightAsInt = StaticValue::fromReturnedValue(right.constant).toInt32();
if (left.isConstant()) {
- int result = Value::fromReturnedValue(left.constant).toInt32() & rightAsInt;
+ int result = StaticValue::fromReturnedValue(left.constant).toInt32() & rightAsInt;
return Reference::fromConst(this, Encode(result));
}
left.loadInAccumulator();
@@ -1557,9 +1580,9 @@ Codegen::Reference Codegen::binopHelper(QSOperator::Op oper, Reference &left, Re
break;
case QSOperator::BitOr:
if (right.isConstant()) {
- int rightAsInt = Value::fromReturnedValue(right.constant).toInt32();
+ int rightAsInt = StaticValue::fromReturnedValue(right.constant).toInt32();
if (left.isConstant()) {
- int result = Value::fromReturnedValue(left.constant).toInt32() | rightAsInt;
+ int result = StaticValue::fromReturnedValue(left.constant).toInt32() | rightAsInt;
return Reference::fromConst(this, Encode(result));
}
left.loadInAccumulator();
@@ -1575,9 +1598,9 @@ Codegen::Reference Codegen::binopHelper(QSOperator::Op oper, Reference &left, Re
break;
case QSOperator::BitXor:
if (right.isConstant()) {
- int rightAsInt = Value::fromReturnedValue(right.constant).toInt32();
+ int rightAsInt = StaticValue::fromReturnedValue(right.constant).toInt32();
if (left.isConstant()) {
- int result = Value::fromReturnedValue(left.constant).toInt32() ^ rightAsInt;
+ int result = StaticValue::fromReturnedValue(left.constant).toInt32() ^ rightAsInt;
return Reference::fromConst(this, Encode(result));
}
left.loadInAccumulator();
@@ -1595,7 +1618,7 @@ Codegen::Reference Codegen::binopHelper(QSOperator::Op oper, Reference &left, Re
if (right.isConstant()) {
left.loadInAccumulator();
Instruction::UShrConst ushr;
- ushr.rhs = Value::fromReturnedValue(right.constant).toInt32() & 0x1f;
+ ushr.rhs = StaticValue::fromReturnedValue(right.constant).toInt32() & 0x1f;
bytecodeGenerator->addInstruction(ushr);
} else {
right.loadInAccumulator();
@@ -1608,7 +1631,7 @@ Codegen::Reference Codegen::binopHelper(QSOperator::Op oper, Reference &left, Re
if (right.isConstant()) {
left.loadInAccumulator();
Instruction::ShrConst shr;
- shr.rhs = Value::fromReturnedValue(right.constant).toInt32() & 0x1f;
+ shr.rhs = StaticValue::fromReturnedValue(right.constant).toInt32() & 0x1f;
bytecodeGenerator->addInstruction(shr);
} else {
right.loadInAccumulator();
@@ -1621,7 +1644,7 @@ Codegen::Reference Codegen::binopHelper(QSOperator::Op oper, Reference &left, Re
if (right.isConstant()) {
left.loadInAccumulator();
Instruction::ShlConst shl;
- shl.rhs = Value::fromReturnedValue(right.constant).toInt32() & 0x1f;
+ shl.rhs = StaticValue::fromReturnedValue(right.constant).toInt32() & 0x1f;
bytecodeGenerator->addInstruction(shl);
} else {
right.loadInAccumulator();
@@ -1749,7 +1772,7 @@ Codegen::Reference Codegen::jumpBinop(QSOperator::Op oper, Reference &left, Refe
qSwap(left, right); // null==a -> a==null
if (right.isConstant()) {
- Value c = Value::fromReturnedValue(right.constant);
+ StaticValue c = StaticValue::fromReturnedValue(right.constant);
if (c.isNull() || c.isUndefined()) {
left.loadInAccumulator();
if (oper == QSOperator::Equal) {
@@ -1851,7 +1874,7 @@ Codegen::Reference Codegen::jumpBinop(QSOperator::Op oper, Reference &left, Refe
bool Codegen::visit(CallExpression *ast)
{
- if (hasError)
+ if (hasError())
return false;
RegisterScope scope(this);
@@ -1859,7 +1882,7 @@ bool Codegen::visit(CallExpression *ast)
Reference base = expression(ast->base);
- if (hasError)
+ if (hasError())
return false;
switch (base.type) {
case Reference::Member:
@@ -1882,7 +1905,7 @@ bool Codegen::visit(CallExpression *ast)
int functionObject = bytecodeGenerator->newRegister();
auto calldata = pushArgs(ast->arguments);
- if (hasError)
+ if (hasError())
return false;
blockTailCalls.unblock();
@@ -1903,7 +1926,7 @@ bool Codegen::visit(CallExpression *ast)
call.thisObject = baseObject.stackSlot();
call.argc = calldata.argc;
call.argv = calldata.argv;
- bytecodeGenerator->addTracingInstruction(call);
+ bytecodeGenerator->addInstruction(call);
} else {
Instruction::TailCall call;
call.func = base.stackSlot();
@@ -1932,14 +1955,14 @@ void Codegen::handleCall(Reference &base, Arguments calldata, int slotForFunctio
call.lookupIndex = registerGetterLookup(base.propertyNameIndex);
call.argc = calldata.argc;
call.argv = calldata.argv;
- bytecodeGenerator->addTracingInstruction(call);
+ bytecodeGenerator->addInstruction(call);
} else {
Instruction::CallProperty call;
call.base = base.propertyBase.stackSlot();
call.name = base.propertyNameIndex;
call.argc = calldata.argc;
call.argv = calldata.argv;
- bytecodeGenerator->addTracingInstruction(call);
+ bytecodeGenerator->addInstruction(call);
}
} else if (base.type == Reference::Subscript) {
Instruction::CallElement call;
@@ -1947,33 +1970,33 @@ void Codegen::handleCall(Reference &base, Arguments calldata, int slotForFunctio
call.index = base.elementSubscript.stackSlot();
call.argc = calldata.argc;
call.argv = calldata.argv;
- bytecodeGenerator->addTracingInstruction(call);
+ bytecodeGenerator->addInstruction(call);
} else if (base.type == Reference::Name) {
if (base.name == QStringLiteral("eval")) {
Instruction::CallPossiblyDirectEval call;
call.argc = calldata.argc;
call.argv = calldata.argv;
- bytecodeGenerator->addTracingInstruction(call);
+ bytecodeGenerator->addInstruction(call);
} else if (!disable_lookups && useFastLookups && base.global) {
if (base.qmlGlobal) {
Instruction::CallQmlContextPropertyLookup call;
call.index = registerQmlContextPropertyGetterLookup(base.nameAsIndex());
call.argc = calldata.argc;
call.argv = calldata.argv;
- bytecodeGenerator->addTracingInstruction(call);
+ bytecodeGenerator->addInstruction(call);
} else {
Instruction::CallGlobalLookup call;
call.index = registerGlobalGetterLookup(base.nameAsIndex());
call.argc = calldata.argc;
call.argv = calldata.argv;
- bytecodeGenerator->addTracingInstruction(call);
+ bytecodeGenerator->addInstruction(call);
}
} else {
Instruction::CallName call;
call.name = base.nameAsIndex();
call.argc = calldata.argc;
call.argv = calldata.argv;
- bytecodeGenerator->addTracingInstruction(call);
+ bytecodeGenerator->addInstruction(call);
}
} else if (base.type == Reference::SuperProperty) {
Reference receiver = base.baseObject();
@@ -1990,14 +2013,14 @@ void Codegen::handleCall(Reference &base, Arguments calldata, int slotForFunctio
call.thisObject = receiver.stackSlot();
call.argc = calldata.argc;
call.argv = calldata.argv;
- bytecodeGenerator->addTracingInstruction(call);
+ bytecodeGenerator->addInstruction(call);
} else {
Q_ASSERT(base.isStackSlot());
Instruction::CallValue call;
call.name = base.stackSlot();
call.argc = calldata.argc;
call.argv = calldata.argv;
- bytecodeGenerator->addTracingInstruction(call);
+ bytecodeGenerator->addInstruction(call);
}
setExprResult(Reference::fromAccumulator(this));
@@ -2023,12 +2046,14 @@ Codegen::Arguments Codegen::pushArgs(ArgumentList *args)
argc = 0;
for (ArgumentList *it = args; it; it = it->next) {
if (it->isSpreadElement) {
- Reference::fromConst(this, Value::emptyValue().asReturnedValue()).storeOnStack(calldata + argc);
+ Reference::fromConst(
+ this,
+ StaticValue::emptyValue().asReturnedValue()).storeOnStack(calldata + argc);
++argc;
}
RegisterScope scope(this);
Reference e = expression(it->expression);
- if (hasError)
+ if (hasError())
break;
if (!argc && !it->next && !hasSpread) {
// avoid copy for functions taking a single argument
@@ -2057,7 +2082,7 @@ Codegen::Arguments Codegen::pushTemplateArgs(TemplateLiteral *args)
for (TemplateLiteral *it = args; it && it->expression; it = it->next) {
RegisterScope scope(this);
Reference e = expression(it->expression);
- if (hasError)
+ if (hasError())
break;
(void) e.storeOnStack(calldata + argc);
++argc;
@@ -2068,7 +2093,7 @@ Codegen::Arguments Codegen::pushTemplateArgs(TemplateLiteral *args)
bool Codegen::visit(ConditionalExpression *ast)
{
- if (hasError)
+ if (hasError())
return false;
RegisterScope scope(this);
@@ -2082,14 +2107,14 @@ bool Codegen::visit(ConditionalExpression *ast)
iftrue.link();
Reference ok = expression(ast->ok);
- if (hasError)
+ if (hasError())
return false;
ok.loadInAccumulator();
BytecodeGenerator::Jump jump_endif = bytecodeGenerator->jump();
iffalse.link();
Reference ko = expression(ast->ko);
- if (hasError) {
+ if (hasError()) {
jump_endif.link(); // dummy link, to prevent assert in Jump destructor from triggering
return false;
}
@@ -2103,13 +2128,13 @@ bool Codegen::visit(ConditionalExpression *ast)
bool Codegen::visit(DeleteExpression *ast)
{
- if (hasError)
+ if (hasError())
return false;
RegisterScope scope(this);
TailCallBlocker blockTailCalls(this);
Reference expr = expression(ast->expression);
- if (hasError)
+ if (hasError())
return false;
switch (expr.type) {
@@ -2174,7 +2199,7 @@ bool Codegen::visit(DeleteExpression *ast)
bool Codegen::visit(FalseLiteral *)
{
- if (hasError)
+ if (hasError())
return false;
setExprResult(Reference::fromConst(this, QV4::Encode(false)));
@@ -2183,7 +2208,7 @@ bool Codegen::visit(FalseLiteral *)
bool Codegen::visit(SuperLiteral *)
{
- if (hasError)
+ if (hasError())
return false;
setExprResult(Reference::fromSuper(this));
@@ -2192,7 +2217,7 @@ bool Codegen::visit(SuperLiteral *)
bool Codegen::visit(FieldMemberExpression *ast)
{
- if (hasError)
+ if (hasError())
return false;
TailCallBlocker blockTailCalls(this);
@@ -2215,7 +2240,7 @@ bool Codegen::visit(FieldMemberExpression *ast)
}
Reference base = expression(ast->base);
- if (hasError)
+ if (hasError())
return false;
if (base.isSuper()) {
Instruction::LoadRuntimeString load;
@@ -2231,7 +2256,7 @@ bool Codegen::visit(FieldMemberExpression *ast)
bool Codegen::visit(TaggedTemplate *ast)
{
- if (hasError)
+ if (hasError())
return false;
RegisterScope scope(this);
@@ -2240,7 +2265,7 @@ bool Codegen::visit(TaggedTemplate *ast)
bool Codegen::handleTaggedTemplate(Reference base, TaggedTemplate *ast)
{
- if (hasError)
+ if (hasError())
return false;
int functionObject = -1, thisObject = -1;
@@ -2264,7 +2289,7 @@ bool Codegen::handleTaggedTemplate(Reference base, TaggedTemplate *ast)
int templateObjectTemp = Reference::fromAccumulator(this).storeOnStack().stackSlot();
Q_UNUSED(templateObjectTemp);
auto calldata = pushTemplateArgs(ast->templateLiteral);
- if (hasError)
+ if (hasError())
return false;
++calldata.argc;
Q_ASSERT(calldata.argv == templateObjectTemp + 1);
@@ -2293,7 +2318,7 @@ void Codegen::createTemplateObject(TemplateLiteral *t)
bool Codegen::visit(FunctionExpression *ast)
{
- if (hasError)
+ if (hasError())
return false;
TailCallBlocker blockTailCalls(this);
@@ -2301,7 +2326,7 @@ bool Codegen::visit(FunctionExpression *ast)
RegisterScope scope(this);
int function = defineFunction(ast->name.toString(), ast, ast->formals, ast->body);
- if (hasError)
+ if (hasError())
return false;
loadClosure(function);
setExprResult(Reference::fromAccumulator(this));
@@ -2357,7 +2382,7 @@ void Codegen::loadClosure(int closureId)
bool Codegen::visit(IdentifierExpression *ast)
{
- if (hasError)
+ if (hasError())
return false;
setExprResult(referenceForName(ast->name.toString(), false, ast->firstSourceLocation()));
@@ -2366,7 +2391,7 @@ bool Codegen::visit(IdentifierExpression *ast)
bool Codegen::visit(NestedExpression *ast)
{
- if (hasError)
+ if (hasError())
return false;
accept(ast->expression);
@@ -2385,7 +2410,7 @@ void Codegen::handleConstruct(const Reference &base, ArgumentList *arguments)
}
auto calldata = pushArgs(arguments);
- if (hasError)
+ if (hasError())
return;
if (base.isSuper())
@@ -2415,14 +2440,14 @@ void Codegen::handleConstruct(const Reference &base, ArgumentList *arguments)
bool Codegen::visit(NewExpression *ast)
{
- if (hasError)
+ if (hasError())
return false;
RegisterScope scope(this);
TailCallBlocker blockTailCalls(this);
Reference base = expression(ast->expression);
- if (hasError)
+ if (hasError())
return false;
if (base.isSuper()) {
throwSyntaxError(ast->expression->firstSourceLocation(), QStringLiteral("Cannot use new with super."));
@@ -2435,14 +2460,14 @@ bool Codegen::visit(NewExpression *ast)
bool Codegen::visit(NewMemberExpression *ast)
{
- if (hasError)
+ if (hasError())
return false;
RegisterScope scope(this);
TailCallBlocker blockTailCalls(this);
Reference base = expression(ast->base);
- if (hasError)
+ if (hasError())
return false;
if (base.isSuper()) {
throwSyntaxError(ast->base->firstSourceLocation(), QStringLiteral("Cannot use new with super."));
@@ -2455,7 +2480,7 @@ bool Codegen::visit(NewMemberExpression *ast)
bool Codegen::visit(NotExpression *ast)
{
- if (hasError)
+ if (hasError())
return false;
TailCallBlocker blockTailCalls(this);
@@ -2465,7 +2490,7 @@ bool Codegen::visit(NotExpression *ast)
bool Codegen::visit(NullExpression *)
{
- if (hasError)
+ if (hasError())
return false;
if (exprAccept(cx))
@@ -2478,7 +2503,7 @@ bool Codegen::visit(NullExpression *)
bool Codegen::visit(NumericLiteral *ast)
{
- if (hasError)
+ if (hasError())
return false;
setExprResult(Reference::fromConst(this, QV4::Encode::smallestNumber(ast->value)));
@@ -2487,7 +2512,7 @@ bool Codegen::visit(NumericLiteral *ast)
bool Codegen::visit(ObjectPattern *ast)
{
- if (hasError)
+ if (hasError())
return false;
TailCallBlocker blockTailCalls(this);
@@ -2513,7 +2538,7 @@ bool Codegen::visit(ObjectPattern *ast)
if (cname || p->type != PatternProperty::Literal)
break;
QString name = p->name->asString();
- uint arrayIndex = QV4::String::toArrayIndex(name);
+ uint arrayIndex = stringToArrayIndex(name);
if (arrayIndex != UINT_MAX)
break;
if (members.contains(name))
@@ -2523,7 +2548,7 @@ bool Codegen::visit(ObjectPattern *ast)
{
RegisterScope innerScope(this);
Reference value = expression(p->initializer, name);
- if (hasError)
+ if (hasError())
return false;
value.loadInAccumulator();
}
@@ -2550,7 +2575,7 @@ bool Codegen::visit(ObjectPattern *ast)
if (cname) {
RegisterScope innerScope(this);
Reference name = expression(cname->expression);
- if (hasError)
+ if (hasError())
return false;
name.loadInAccumulator();
} else {
@@ -2575,12 +2600,12 @@ bool Codegen::visit(ObjectPattern *ast)
FunctionExpression *f = p->initializer->asFunctionDefinition();
Q_ASSERT(f);
int function = defineFunction(f->name.toString(), f, f->formals, f->body);
- if (hasError)
+ if (hasError())
return false;
Reference::fromConst(this, Encode(function)).loadInAccumulator();
} else {
Reference value = expression(p->initializer);
- if (hasError)
+ if (hasError())
return false;
value.loadInAccumulator();
}
@@ -2599,11 +2624,11 @@ bool Codegen::visit(ObjectPattern *ast)
bool Codegen::visit(PostDecrementExpression *ast)
{
- if (hasError)
+ if (hasError())
return false;
Reference expr = expression(ast->base);
- if (hasError)
+ if (hasError())
return false;
if (!expr.isLValue()) {
throwReferenceError(ast->base->lastSourceLocation(), QStringLiteral("Invalid left-hand side expression in postfix operation"));
@@ -2619,11 +2644,11 @@ bool Codegen::visit(PostDecrementExpression *ast)
bool Codegen::visit(PostIncrementExpression *ast)
{
- if (hasError)
+ if (hasError())
return false;
Reference expr = expression(ast->base);
- if (hasError)
+ if (hasError())
return false;
if (!expr.isLValue()) {
throwReferenceError(ast->base->lastSourceLocation(), QStringLiteral("Invalid left-hand side expression in postfix operation"));
@@ -2637,11 +2662,11 @@ bool Codegen::visit(PostIncrementExpression *ast)
}
bool Codegen::visit(PreDecrementExpression *ast)
-{ if (hasError)
+{ if (hasError())
return false;
Reference expr = expression(ast->expression);
- if (hasError)
+ if (hasError())
return false;
if (!expr.isLValue()) {
throwReferenceError(ast->expression->lastSourceLocation(), QStringLiteral("Prefix ++ operator applied to value that is not a reference."));
@@ -2656,11 +2681,11 @@ bool Codegen::visit(PreDecrementExpression *ast)
bool Codegen::visit(PreIncrementExpression *ast)
{
- if (hasError)
+ if (hasError())
return false;
Reference expr = expression(ast->expression);
- if (hasError)
+ if (hasError())
return false;
if (!expr.isLValue()) {
throwReferenceError(ast->expression->lastSourceLocation(), QStringLiteral("Prefix ++ operator applied to value that is not a reference."));
@@ -2675,7 +2700,7 @@ bool Codegen::visit(PreIncrementExpression *ast)
bool Codegen::visit(RegExpLiteral *ast)
{
- if (hasError)
+ if (hasError())
return false;
auto r = Reference::fromStackSlot(this);
@@ -2691,7 +2716,7 @@ bool Codegen::visit(RegExpLiteral *ast)
bool Codegen::visit(StringLiteral *ast)
{
- if (hasError)
+ if (hasError())
return false;
auto r = Reference::fromAccumulator(this);
@@ -2706,7 +2731,7 @@ bool Codegen::visit(StringLiteral *ast)
bool Codegen::visit(TemplateLiteral *ast)
{
- if (hasError)
+ if (hasError())
return false;
TailCallBlocker blockTailCalls(this);
@@ -2723,7 +2748,7 @@ bool Codegen::visit(TemplateLiteral *ast)
bytecodeGenerator->addInstruction(store);
Reference expr = expression(ast->expression);
- if (hasError)
+ if (hasError())
return false;
if (ast->next) {
@@ -2733,14 +2758,14 @@ bool Codegen::visit(TemplateLiteral *ast)
Instruction::Add instr;
instr.lhs = temp2;
- bytecodeGenerator->addTracingInstruction(instr);
+ bytecodeGenerator->addInstruction(instr);
} else {
expr.loadInAccumulator();
}
Instruction::Add instr;
instr.lhs = temp;
- bytecodeGenerator->addTracingInstruction(instr);
+ bytecodeGenerator->addInstruction(instr);
}
auto r = Reference::fromAccumulator(this);
@@ -2753,7 +2778,7 @@ bool Codegen::visit(TemplateLiteral *ast)
bool Codegen::visit(ThisExpression *)
{
- if (hasError)
+ if (hasError())
return false;
if (_context->isArrowFunction) {
@@ -2768,7 +2793,7 @@ bool Codegen::visit(ThisExpression *)
bool Codegen::visit(TildeExpression *ast)
{
- if (hasError)
+ if (hasError())
return false;
TailCallBlocker blockTailCalls(this);
@@ -2778,7 +2803,7 @@ bool Codegen::visit(TildeExpression *ast)
bool Codegen::visit(TrueLiteral *)
{
- if (hasError)
+ if (hasError())
return false;
setExprResult(Reference::fromConst(this, QV4::Encode(true)));
@@ -2787,14 +2812,14 @@ bool Codegen::visit(TrueLiteral *)
bool Codegen::visit(TypeOfExpression *ast)
{
- if (hasError)
+ if (hasError())
return false;
RegisterScope scope(this);
TailCallBlocker blockTailCalls(this);
Reference expr = expression(ast->expression);
- if (hasError)
+ if (hasError())
return false;
if (expr.type == Reference::Name) {
@@ -2814,7 +2839,7 @@ bool Codegen::visit(TypeOfExpression *ast)
bool Codegen::visit(UnaryMinusExpression *ast)
{
- if (hasError)
+ if (hasError())
return false;
TailCallBlocker blockTailCalls(this);
@@ -2824,7 +2849,7 @@ bool Codegen::visit(UnaryMinusExpression *ast)
bool Codegen::visit(UnaryPlusExpression *ast)
{
- if (hasError)
+ if (hasError())
return false;
TailCallBlocker blockTailCalls(this);
@@ -2834,7 +2859,7 @@ bool Codegen::visit(UnaryPlusExpression *ast)
bool Codegen::visit(VoidExpression *ast)
{
- if (hasError)
+ if (hasError())
return false;
RegisterScope scope(this);
@@ -2847,7 +2872,7 @@ bool Codegen::visit(VoidExpression *ast)
bool Codegen::visit(FunctionDeclaration * ast)
{
- if (hasError)
+ if (hasError())
return false;
// no need to block tail calls: the function body isn't visited here.
@@ -2869,7 +2894,7 @@ bool Codegen::visit(YieldExpression *ast)
RegisterScope scope(this);
TailCallBlocker blockTailCalls(this);
Reference expr = ast->expression ? expression(ast->expression) : Reference::fromConst(this, Encode::undefined());
- if (hasError)
+ if (hasError())
return false;
Reference acc = Reference::fromAccumulator(this);
@@ -2998,10 +3023,10 @@ int Codegen::defineFunction(const QString &name, AST::Node *ast,
bool savedFunctionEndsWithReturn = functionEndsWithReturn;
functionEndsWithReturn = endsWithReturn(_module, body);
- bytecodeGenerator->setTracing(_functionContext->canUseTracingJit(), _context->arguments.size());
// reserve the js stack frame (Context & js Function & accumulator)
- bytecodeGenerator->newRegisterArray(sizeof(CallData)/sizeof(Value) - 1 + _context->arguments.size());
+ bytecodeGenerator->newRegisterArray(
+ sizeof(CallData) / sizeof(StaticValue) - 1 + _context->arguments.size());
bool _inFormalParameterList = false;
qSwap(_inFormalParameterList, inFormalParameterList);
@@ -3047,7 +3072,7 @@ int Codegen::defineFunction(const QString &name, AST::Node *ast,
} else {
if (e->bindingTarget || e->initializer) {
initializeAndDestructureBindingElement(e, arg);
- if (hasError)
+ if (hasError())
break;
}
}
@@ -3063,7 +3088,7 @@ int Codegen::defineFunction(const QString &name, AST::Node *ast,
statementList(body);
- if (!hasError) {
+ if (!hasError()) {
bytecodeGenerator->setLocation(ast->lastSourceLocation());
_context->emitBlockFooter(this);
@@ -3085,7 +3110,6 @@ int Codegen::defineFunction(const QString &name, AST::Node *ast,
Q_ASSERT(_context == _functionContext);
bytecodeGenerator->finalize(_context);
_context->registerCountInFunction = bytecodeGenerator->registerCount();
- _context->nTraceInfos = bytecodeGenerator->traceInfoCount();
static const bool showCode = qEnvironmentVariableIsSet("QV4_SHOW_BYTECODE");
if (showCode) {
qDebug() << "=== Bytecode for" << _context->name << "strict mode" << _context->isStrict
@@ -3111,7 +3135,7 @@ int Codegen::defineFunction(const QString &name, AST::Node *ast,
bool Codegen::visit(Block *ast)
{
- if (hasError)
+ if (hasError())
return false;
RegisterScope scope(this);
@@ -3123,7 +3147,7 @@ bool Codegen::visit(Block *ast)
bool Codegen::visit(BreakStatement *ast)
{
- if (hasError)
+ if (hasError())
return false;
// no need to block tail calls here: children aren't visited
@@ -3148,7 +3172,7 @@ bool Codegen::visit(BreakStatement *ast)
bool Codegen::visit(ContinueStatement *ast)
{
- if (hasError)
+ if (hasError())
return false;
// no need to block tail calls here: children aren't visited
@@ -3181,7 +3205,7 @@ bool Codegen::visit(DebuggerStatement *)
bool Codegen::visit(DoWhileStatement *ast)
{
- if (hasError)
+ if (hasError())
return false;
RegisterScope scope(this);
@@ -3191,22 +3215,28 @@ bool Codegen::visit(DoWhileStatement *ast)
BytecodeGenerator::Label end = bytecodeGenerator->newLabel();
ControlFlowLoop flow(this, &end, &cond);
- bytecodeGenerator->jump().link(body);
-
- cond.link();
- bytecodeGenerator->addLoopStart(cond);
- if (!AST::cast<TrueLiteral *>(ast->expression)) {
- TailCallBlocker blockTailCalls(this);
- condition(ast->expression, &body, &end, true);
- }
+ // special case that is not a loop:
+ // do {...} while (false)
+ if (!AST::cast<FalseLiteral *>(ast->expression))
+ bytecodeGenerator->addLoopStart(body);
body.link();
statement(ast->statement);
setJumpOutLocation(bytecodeGenerator, ast->statement, ast->semicolonToken);
- if (!AST::cast<FalseLiteral *>(ast->expression))
- bytecodeGenerator->jump().link(cond);
+ cond.link();
+ if (AST::cast<TrueLiteral *>(ast->expression)) {
+ // do {} while (true) -> just jump back to the loop body, no need to generate a condition
+ bytecodeGenerator->checkException();
+ bytecodeGenerator->jump().link(body);
+ } else if (AST::cast<FalseLiteral *>(ast->expression)) {
+ // do {} while (false) -> fall through, no need to generate a condition
+ } else {
+ TailCallBlocker blockTailCalls(this);
+ bytecodeGenerator->checkException();
+ condition(ast->expression, &body, &end, false);
+ }
end.link();
@@ -3220,7 +3250,7 @@ bool Codegen::visit(EmptyStatement *)
bool Codegen::visit(ExpressionStatement *ast)
{
- if (hasError)
+ if (hasError())
return false;
RegisterScope scope(this);
@@ -3228,7 +3258,7 @@ bool Codegen::visit(ExpressionStatement *ast)
if (requiresReturnValue) {
Reference e = expression(ast->expression);
- if (hasError)
+ if (hasError())
return false;
(void) e.storeOnStack(_returnAddress);
} else {
@@ -3239,7 +3269,7 @@ bool Codegen::visit(ExpressionStatement *ast)
bool Codegen::visit(ForEachStatement *ast)
{
- if (hasError)
+ if (hasError())
return false;
RegisterScope scope(this);
@@ -3255,7 +3285,7 @@ bool Codegen::visit(ForEachStatement *ast)
RegisterScope innerScope(this);
ControlFlowBlock controlFlow(this, ast);
Reference expr = expression(ast->expression);
- if (hasError)
+ if (hasError())
return false;
expr.loadInAccumulator();
@@ -3285,7 +3315,7 @@ bool Codegen::visit(ForEachStatement *ast)
next.value = lhsValue.stackSlot();
next.done = iteratorDone.stackSlot();
bytecodeGenerator->addInstruction(next);
- bytecodeGenerator->addTracingJumpInstruction(Instruction::JumpTrue()).link(end);
+ bytecodeGenerator->addJumpInstruction(Instruction::JumpTrue()).link(end);
// each iteration gets it's own context, as per spec
{
@@ -3298,7 +3328,7 @@ bool Codegen::visit(ForEachStatement *ast)
destructurePattern(p, lhsValue);
} else {
Reference lhs = expression(e);
- if (hasError)
+ if (hasError())
goto error;
if (!lhs.isLValue()) {
throwReferenceError(e->firstSourceLocation(), QStringLiteral("Invalid left-hand side expression for 'in' expression"));
@@ -3310,7 +3340,7 @@ bool Codegen::visit(ForEachStatement *ast)
}
} else if (PatternElement *p = AST::cast<PatternElement *>(ast->lhs)) {
initializeAndDestructureBindingElement(p, lhsValue, /*isDefinition =*/ true);
- if (hasError)
+ if (hasError())
goto error;
} else {
Q_UNREACHABLE();
@@ -3321,6 +3351,7 @@ bool Codegen::visit(ForEachStatement *ast)
setJumpOutLocation(bytecodeGenerator, ast->statement, ast->forToken);
}
+ bytecodeGenerator->checkException();
bytecodeGenerator->jump().link(in);
error:
@@ -3335,7 +3366,7 @@ bool Codegen::visit(ForEachStatement *ast)
bool Codegen::visit(ForStatement *ast)
{
- if (hasError)
+ if (hasError())
return false;
RegisterScope scope(this);
@@ -3369,6 +3400,7 @@ bool Codegen::visit(ForStatement *ast)
bytecodeGenerator->addInstruction(clone);
}
statement(ast->expression);
+ bytecodeGenerator->checkException();
bytecodeGenerator->jump().link(cond);
end.link();
@@ -3378,7 +3410,7 @@ bool Codegen::visit(ForStatement *ast)
bool Codegen::visit(IfStatement *ast)
{
- if (hasError)
+ if (hasError())
return false;
RegisterScope scope(this);
@@ -3410,7 +3442,7 @@ bool Codegen::visit(IfStatement *ast)
bool Codegen::visit(LabelledStatement *ast)
{
- if (hasError)
+ if (hasError())
return false;
RegisterScope scope(this);
@@ -3458,7 +3490,7 @@ void Codegen::emitReturn(const Reference &expr)
bool Codegen::visit(ReturnStatement *ast)
{
- if (hasError)
+ if (hasError())
return false;
if (_functionContext->contextType != ContextType::Function && _functionContext->contextType != ContextType::Binding) {
@@ -3468,7 +3500,7 @@ bool Codegen::visit(ReturnStatement *ast)
Reference expr;
if (ast->expression) {
expr = expression(ast->expression);
- if (hasError)
+ if (hasError())
return false;
} else {
expr = Reference::fromConst(this, Encode::undefined());
@@ -3481,7 +3513,7 @@ bool Codegen::visit(ReturnStatement *ast)
bool Codegen::visit(SwitchStatement *ast)
{
- if (hasError)
+ if (hasError())
return false;
if (requiresReturnValue)
@@ -3494,7 +3526,7 @@ bool Codegen::visit(SwitchStatement *ast)
BytecodeGenerator::Label switchEnd = bytecodeGenerator->newLabel();
Reference lhs = expression(ast->expression);
- if (hasError)
+ if (hasError())
return false;
lhs = lhs.storeOnStack();
@@ -3513,7 +3545,7 @@ bool Codegen::visit(SwitchStatement *ast)
for (CaseClauses *it = ast->block->clauses; it; it = it->next) {
CaseClause *clause = it->clause;
Reference rhs = expression(clause->expression);
- if (hasError)
+ if (hasError())
return false;
rhs.loadInAccumulator();
bytecodeGenerator->jumpStrictEqual(lhs.stackSlot(), blockMap.value(clause));
@@ -3522,7 +3554,7 @@ bool Codegen::visit(SwitchStatement *ast)
for (CaseClauses *it = ast->block->moreClauses; it; it = it->next) {
CaseClause *clause = it->clause;
Reference rhs = expression(clause->expression);
- if (hasError)
+ if (hasError())
return false;
rhs.loadInAccumulator();
bytecodeGenerator->jumpStrictEqual(lhs.stackSlot(), blockMap.value(clause));
@@ -3568,14 +3600,14 @@ bool Codegen::visit(SwitchStatement *ast)
bool Codegen::visit(ThrowStatement *ast)
{
- if (hasError)
+ if (hasError())
return false;
RegisterScope scope(this);
TailCallBlocker blockTailCalls(this);
Reference expr = expression(ast->expression);
- if (hasError)
+ if (hasError())
return false;
expr.loadInAccumulator();
@@ -3612,7 +3644,7 @@ void Codegen::handleTryFinally(TryStatement *ast)
bool Codegen::visit(TryStatement *ast)
{
- if (hasError)
+ if (hasError())
return false;
RegisterScope scope(this);
@@ -3628,7 +3660,7 @@ bool Codegen::visit(TryStatement *ast)
bool Codegen::visit(VariableStatement *ast)
{
- if (hasError)
+ if (hasError())
return false;
variableDeclarationList(ast->declarations);
@@ -3637,7 +3669,7 @@ bool Codegen::visit(VariableStatement *ast)
bool Codegen::visit(WhileStatement *ast)
{
- if (hasError)
+ if (hasError())
return false;
if (AST::cast<FalseLiteral *>(ast->expression))
@@ -3651,6 +3683,8 @@ bool Codegen::visit(WhileStatement *ast)
ControlFlowLoop flow(this, &end, &cond);
bytecodeGenerator->addLoopStart(cond);
+ bytecodeGenerator->checkException();
+
if (!AST::cast<TrueLiteral *>(ast->expression)) {
TailCallBlocker blockTailCalls(this);
condition(ast->expression, &start, &end, true);
@@ -3667,14 +3701,14 @@ bool Codegen::visit(WhileStatement *ast)
bool Codegen::visit(WithStatement *ast)
{
- if (hasError)
+ if (hasError())
return false;
RegisterScope scope(this);
TailCallBlocker blockTailCalls(this);
Reference src = expression(ast->expression);
- if (hasError)
+ if (hasError())
return false;
src = src.storeOnStack(); // trigger load before we setup the exception handler, so exceptions here go to the right place
src.loadInAccumulator();
@@ -3744,52 +3778,79 @@ bool Codegen::throwSyntaxErrorOnEvalOrArgumentsInStrictMode(const Reference &r,
return isArgOrEval;
}
-void Codegen::throwSyntaxError(const SourceLocation &loc, const QString &detail)
+void Codegen::throwError(ErrorType errorType, const SourceLocation &loc, const QString &detail)
{
- if (hasError)
+ if (hasError())
return;
- hasError = true;
- QQmlJS::DiagnosticMessage error;
- error.message = detail;
- error.loc = loc;
- _errors << error;
+ _errorType = errorType;
+ _error.message = detail;
+ _error.line = loc.startLine;
+ _error.column = loc.startColumn;
}
-void Codegen::throwReferenceError(const SourceLocation &loc, const QString &detail)
+void Codegen::throwSyntaxError(const SourceLocation &loc, const QString &detail)
{
- if (hasError)
- return;
-
- hasError = true;
- QQmlJS::DiagnosticMessage error;
- error.message = detail;
- error.loc = loc;
- _errors << error;
+ throwError(SyntaxError, loc, detail);
}
-QList<QQmlJS::DiagnosticMessage> Codegen::errors() const
+void Codegen::throwReferenceError(const SourceLocation &loc, const QString &detail)
{
- return _errors;
+ throwError(ReferenceError, loc, detail);
}
-QQmlRefPointer<CompiledData::CompilationUnit> Codegen::generateCompilationUnit(bool generateUnitData)
+QQmlJS::DiagnosticMessage Codegen::error() const
{
- CompiledData::Unit *unitData = nullptr;
- if (generateUnitData)
- unitData = jsUnitGenerator->generateUnit();
- CompiledData::CompilationUnit *compilationUnit = new CompiledData::CompilationUnit(unitData);
+ return _error;
+}
- QQmlRefPointer<CompiledData::CompilationUnit> unit;
- unit.adopt(compilationUnit);
- return unit;
+QV4::CompiledData::CompilationUnit Codegen::generateCompilationUnit(
+ bool generateUnitData)
+{
+ return QV4::CompiledData::CompilationUnit(
+ generateUnitData ? jsUnitGenerator->generateUnit() : nullptr);
}
-QQmlRefPointer<CompiledData::CompilationUnit> Codegen::createUnitForLoading()
+CompiledData::CompilationUnit Codegen::compileModule(
+ bool debugMode, const QString &url, const QString &sourceCode,
+ const QDateTime &sourceTimeStamp, QList<QQmlJS::DiagnosticMessage> *diagnostics)
{
- QQmlRefPointer<CompiledData::CompilationUnit> result;
- result.adopt(new CompiledData::CompilationUnit);
- return result;
+ QQmlJS::Engine ee;
+ QQmlJS::Lexer lexer(&ee);
+ lexer.setCode(sourceCode, /*line*/1, /*qml mode*/false);
+ QQmlJS::Parser parser(&ee);
+
+ const bool parsed = parser.parseModule();
+
+ if (diagnostics)
+ *diagnostics = parser.diagnosticMessages();
+
+ if (!parsed)
+ return CompiledData::CompilationUnit();
+
+ QQmlJS::AST::ESModule *moduleNode = QQmlJS::AST::cast<QQmlJS::AST::ESModule*>(parser.rootNode());
+ if (!moduleNode) {
+ // if parsing was successful, and we have no module, then
+ // the file was empty.
+ if (diagnostics)
+ diagnostics->clear();
+ return nullptr;
+ }
+
+ using namespace QV4::Compiler;
+ Compiler::Module compilerModule(debugMode);
+ compilerModule.unitFlags |= CompiledData::Unit::IsESModule;
+ compilerModule.sourceTimeStamp = sourceTimeStamp;
+ JSUnitGenerator jsGenerator(&compilerModule);
+ Codegen cg(&jsGenerator, /*strictMode*/true);
+ cg.generateFromModule(url, url, sourceCode, moduleNode, &compilerModule);
+ if (cg.hasError()) {
+ if (diagnostics)
+ *diagnostics << cg.error();
+ return CompiledData::CompilationUnit();
+ }
+
+ return cg.generateCompilationUnit();
}
class Codegen::VolatileMemoryLocationScanner: protected QQmlJS::AST::Visitor
@@ -3905,34 +3966,11 @@ Codegen::VolatileMemoryLocations Codegen::scanVolatileMemoryLocations(AST::Node
return scanner.scan(ast);
}
-
-#ifndef V4_BOOTSTRAP
-
-QList<QQmlError> Codegen::qmlErrors() const
+QUrl Codegen::url() const
{
- QList<QQmlError> qmlErrors;
-
- // Short circuit to avoid costly (de)heap allocation of QUrl if there are no errors.
- if (_errors.size() == 0)
- return qmlErrors;
-
- qmlErrors.reserve(_errors.size());
-
- QUrl url(_fileNameIsUrl ? QUrl(_module->fileName) : QUrl::fromLocalFile(_module->fileName));
- for (const QQmlJS::DiagnosticMessage &msg: qAsConst(_errors)) {
- QQmlError e;
- e.setUrl(url);
- e.setLine(msg.loc.startLine);
- e.setColumn(msg.loc.startColumn);
- e.setDescription(msg.message);
- qmlErrors << e;
- }
-
- return qmlErrors;
+ return QUrl(_fileNameIsUrl ? QUrl(_module->fileName) : QUrl::fromLocalFile(_module->fileName));
}
-#endif // V4_BOOTSTRAP
-
bool Codegen::RValue::operator==(const RValue &other) const
{
switch (type) {
@@ -4222,7 +4260,7 @@ void Codegen::Reference::storeAccumulator() const
Instruction::StoreElement store;
store.base = elementBase;
store.index = elementSubscript.stackSlot();
- codegen->bytecodeGenerator->addTracingInstruction(store);
+ codegen->bytecodeGenerator->addInstruction(store);
} return;
case Invalid:
case Accumulator:
@@ -4280,7 +4318,7 @@ QT_WARNING_DISABLE_GCC("-Wmaybe-uninitialized") // the loads below are empty str
Instruction::LoadUndefined load;
codegen->bytecodeGenerator->addInstruction(load);
} else {
- Value p = Value::fromReturnedValue(constant);
+ StaticValue p = StaticValue::fromReturnedValue(constant);
if (p.isNumber()) {
double d = p.asDouble();
int i = static_cast<int>(d);
@@ -4291,7 +4329,7 @@ QT_WARNING_DISABLE_GCC("-Wmaybe-uninitialized") // the loads below are empty str
return;
}
Instruction::LoadInt load;
- load.value = Value::fromReturnedValue(constant).toInt32();
+ load.value = StaticValue::fromReturnedValue(constant).toInt32();
codegen->bytecodeGenerator->addInstruction(load);
return;
}
@@ -4312,12 +4350,12 @@ QT_WARNING_POP
if (!scope) {
Instruction::LoadLocal load;
load.index = index;
- codegen->bytecodeGenerator->addTracingInstruction(load);
+ codegen->bytecodeGenerator->addInstruction(load);
} else {
Instruction::LoadScopedLocal load;
load.index = index;
load.scope = scope;
- codegen->bytecodeGenerator->addTracingInstruction(load);
+ codegen->bytecodeGenerator->addInstruction(load);
}
tdzCheck(requiresTDZCheck);
return;
@@ -4341,16 +4379,16 @@ QT_WARNING_POP
if (qmlGlobal) {
Instruction::LoadQmlContextPropertyLookup load;
load.index = codegen->registerQmlContextPropertyGetterLookup(nameAsIndex());
- codegen->bytecodeGenerator->addTracingInstruction(load);
+ codegen->bytecodeGenerator->addInstruction(load);
} else {
Instruction::LoadGlobalLookup load;
load.index = codegen->registerGlobalGetterLookup(nameAsIndex());
- codegen->bytecodeGenerator->addTracingInstruction(load);
+ codegen->bytecodeGenerator->addInstruction(load);
}
} else {
Instruction::LoadName load;
load.name = nameAsIndex();
- codegen->bytecodeGenerator->addTracingInstruction(load);
+ codegen->bytecodeGenerator->addInstruction(load);
}
return;
case Member:
@@ -4359,11 +4397,11 @@ QT_WARNING_POP
if (!disable_lookups && codegen->useFastLookups) {
Instruction::GetLookup load;
load.index = codegen->registerGetterLookup(propertyNameIndex);
- codegen->bytecodeGenerator->addTracingInstruction(load);
+ codegen->bytecodeGenerator->addInstruction(load);
} else {
Instruction::LoadProperty load;
load.name = propertyNameIndex;
- codegen->bytecodeGenerator->addTracingInstruction(load);
+ codegen->bytecodeGenerator->addInstruction(load);
}
return;
case Import: {
@@ -4378,7 +4416,7 @@ QT_WARNING_POP
tdzCheck(subscriptRequiresTDZCheck);
Instruction::LoadElement load;
load.base = elementBase;
- codegen->bytecodeGenerator->addTracingInstruction(load);
+ codegen->bytecodeGenerator->addInstruction(load);
} return;
case Invalid:
break;
diff --git a/src/qml/compiler/qv4codegen_p.h b/src/qml/compiler/qv4codegen_p.h
index 958dd16816..82a4fc3289 100644
--- a/src/qml/compiler/qv4codegen_p.h
+++ b/src/qml/compiler/qv4codegen_p.h
@@ -50,19 +50,18 @@
// We mean it.
//
-#include "private/qv4global_p.h"
#include <private/qqmljsastvisitor_p.h>
+#include <private/qqmljsengine_p.h>
#include <private/qqmljsast_p.h>
+#include <private/qqmljsdiagnosticmessage_p.h>
#include <private/qv4compiler_p.h>
#include <private/qv4compilercontext_p.h>
#include <private/qv4util_p.h>
#include <private/qv4bytecodegenerator_p.h>
-#include <private/qv4stackframe_p.h>
+#include <private/qv4calldata_p.h>
QT_BEGIN_NAMESPACE
-using namespace QQmlJS;
-
namespace QV4 {
namespace Moth {
@@ -79,7 +78,7 @@ struct ControlFlow;
struct ControlFlowCatch;
struct ControlFlowFinally;
-class Q_QML_PRIVATE_EXPORT Codegen: protected QQmlJS::AST::Visitor
+class Q_QMLCOMPILER_PRIVATE_EXPORT Codegen: protected QQmlJS::AST::Visitor
{
protected:
using BytecodeGenerator = QV4::Moth::BytecodeGenerator;
@@ -91,14 +90,14 @@ public:
void generateFromProgram(const QString &fileName,
const QString &finalUrl,
const QString &sourceCode,
- AST::Program *ast,
+ QQmlJS::AST::Program *ast,
Module *module,
ContextType contextType = ContextType::Global);
void generateFromModule(const QString &fileName,
const QString &finalUrl,
const QString &sourceCode,
- AST::ESModule *ast,
+ QQmlJS::AST::ESModule *ast,
Module *module);
public:
@@ -256,7 +255,8 @@ public:
}
static Reference fromArgument(Codegen *cg, int index, bool isVolatile) {
Reference r(cg, StackSlot);
- r.theStackSlot = Moth::StackSlot::createRegister(index + sizeof(CallData)/sizeof(Value) - 1);
+ r.theStackSlot = Moth::StackSlot::createRegister(
+ index + sizeof(CallData) / sizeof(StaticValue) - 1);
r.stackSlotIsLocalOrArgument = true;
r.isVolatile = isVolatile;
return r;
@@ -484,10 +484,10 @@ protected:
}
};
- void enterContext(AST::Node *node);
+ void enterContext(QQmlJS::AST::Node *node);
int leaveContext();
public:
- Context *enterBlock(AST::Node *node);
+ Context *enterBlock(QQmlJS::AST::Node *node);
int leaveBlock() { return leaveContext(); }
protected:
void leaveLoop();
@@ -518,20 +518,20 @@ public:
int registerQmlContextPropertyGetterLookup(int nameIndex) { return jsUnitGenerator->registerQmlContextPropertyGetterLookup(nameIndex); }
// Returns index in _module->functions
- virtual int defineFunction(const QString &name, AST::Node *ast,
- AST::FormalParameterList *formals,
- AST::StatementList *body);
+ virtual int defineFunction(const QString &name, QQmlJS::AST::Node *ast,
+ QQmlJS::AST::FormalParameterList *formals,
+ QQmlJS::AST::StatementList *body);
protected:
- void statement(AST::Statement *ast);
- void statement(AST::ExpressionNode *ast);
- void condition(AST::ExpressionNode *ast, const BytecodeGenerator::Label *iftrue,
+ void statement(QQmlJS::AST::Statement *ast);
+ void statement(QQmlJS::AST::ExpressionNode *ast);
+ void condition(QQmlJS::AST::ExpressionNode *ast, const BytecodeGenerator::Label *iftrue,
const BytecodeGenerator::Label *iffalse,
bool trueBlockFollowsCondition);
- inline Reference expression(AST::ExpressionNode *ast, const QString &name = QString())
+ inline Reference expression(QQmlJS::AST::ExpressionNode *ast, const QString &name = QString())
{
- if (!ast || hasError)
+ if (!ast || hasError())
return Reference();
pushExpr(name);
@@ -539,160 +539,173 @@ protected:
return popResult();
}
- inline void accept(AST::Node *node)
+ inline void accept(QQmlJS::AST::Node *node)
{
- if (!hasError && node)
+ if (!hasError() && node)
node->accept(this);
}
- void program(AST::Program *ast);
- void statementList(AST::StatementList *ast);
- void variableDeclaration(AST::PatternElement *ast);
- void variableDeclarationList(AST::VariableDeclarationList *ast);
+ void program(QQmlJS::AST::Program *ast);
+ void statementList(QQmlJS::AST::StatementList *ast);
+ void variableDeclaration(QQmlJS::AST::PatternElement *ast);
+ void variableDeclarationList(QQmlJS::AST::VariableDeclarationList *ast);
- Reference targetForPatternElement(AST::PatternElement *p);
- void initializeAndDestructureBindingElement(AST::PatternElement *e, const Reference &baseRef = Reference(), bool isDefinition = false);
- void destructurePropertyList(const Reference &object, AST::PatternPropertyList *bindingList, bool isDefinition = false);
- void destructureElementList(const Reference &array, AST::PatternElementList *bindingList, bool isDefinition = false);
- void destructurePattern(AST::Pattern *p, const Reference &rhs);
+ Reference targetForPatternElement(QQmlJS::AST::PatternElement *p);
+ void initializeAndDestructureBindingElement(QQmlJS::AST::PatternElement *e, const Reference &baseRef = Reference(), bool isDefinition = false);
+ void destructurePropertyList(const Reference &object, QQmlJS::AST::PatternPropertyList *bindingList, bool isDefinition = false);
+ void destructureElementList(const Reference &array, QQmlJS::AST::PatternElementList *bindingList, bool isDefinition = false);
+ void destructurePattern(QQmlJS::AST::Pattern *p, const Reference &rhs);
- Reference referenceForPropertyName(const Codegen::Reference &object, AST::PropertyName *name);
+ Reference referenceForPropertyName(const Codegen::Reference &object, QQmlJS::AST::PropertyName *name);
void emitReturn(const Reference &expr);
// nodes
- bool visit(AST::ArgumentList *ast) override;
- bool visit(AST::CaseBlock *ast) override;
- bool visit(AST::CaseClause *ast) override;
- bool visit(AST::CaseClauses *ast) override;
- bool visit(AST::Catch *ast) override;
- bool visit(AST::DefaultClause *ast) override;
- bool visit(AST::Elision *ast) override;
- bool visit(AST::Finally *ast) override;
- bool visit(AST::FormalParameterList *ast) override;
- bool visit(AST::Program *ast) override;
- bool visit(AST::StatementList *ast) override;
- bool visit(AST::UiArrayMemberList *ast) override;
- bool visit(AST::UiImport *ast) override;
- bool visit(AST::UiHeaderItemList *ast) override;
- bool visit(AST::UiPragma *ast) override;
- bool visit(AST::UiObjectInitializer *ast) override;
- bool visit(AST::UiObjectMemberList *ast) override;
- bool visit(AST::UiParameterList *ast) override;
- bool visit(AST::UiProgram *ast) override;
- bool visit(AST::UiQualifiedId *ast) override;
- bool visit(AST::VariableDeclarationList *ast) override;
-
- bool visit(AST::PatternElement *ast) override;
- bool visit(AST::PatternElementList *ast) override;
- bool visit(AST::PatternProperty *ast) override;
- bool visit(AST::PatternPropertyList *ast) override;
-
- bool visit(AST::ExportDeclaration *ast) override;
+ bool visit(QQmlJS::AST::ArgumentList *ast) override;
+ bool visit(QQmlJS::AST::CaseBlock *ast) override;
+ bool visit(QQmlJS::AST::CaseClause *ast) override;
+ bool visit(QQmlJS::AST::CaseClauses *ast) override;
+ bool visit(QQmlJS::AST::Catch *ast) override;
+ bool visit(QQmlJS::AST::DefaultClause *ast) override;
+ bool visit(QQmlJS::AST::Elision *ast) override;
+ bool visit(QQmlJS::AST::Finally *ast) override;
+ bool visit(QQmlJS::AST::FormalParameterList *ast) override;
+ bool visit(QQmlJS::AST::Program *ast) override;
+ bool visit(QQmlJS::AST::StatementList *ast) override;
+ bool visit(QQmlJS::AST::UiArrayMemberList *ast) override;
+ bool visit(QQmlJS::AST::UiImport *ast) override;
+ bool visit(QQmlJS::AST::UiHeaderItemList *ast) override;
+ bool visit(QQmlJS::AST::UiPragma *ast) override;
+ bool visit(QQmlJS::AST::UiObjectInitializer *ast) override;
+ bool visit(QQmlJS::AST::UiObjectMemberList *ast) override;
+ bool visit(QQmlJS::AST::UiParameterList *ast) override;
+ bool visit(QQmlJS::AST::UiProgram *ast) override;
+ bool visit(QQmlJS::AST::UiQualifiedId *ast) override;
+ bool visit(QQmlJS::AST::VariableDeclarationList *ast) override;
+
+ bool visit(QQmlJS::AST::PatternElement *ast) override;
+ bool visit(QQmlJS::AST::PatternElementList *ast) override;
+ bool visit(QQmlJS::AST::PatternProperty *ast) override;
+ bool visit(QQmlJS::AST::PatternPropertyList *ast) override;
+
+ bool visit(QQmlJS::AST::ExportDeclaration *ast) override;
+
+ bool visit(QQmlJS::AST::TypeAnnotation *ast) override;
// expressions
- bool visit(AST::Expression *ast) override;
- bool visit(AST::ArrayPattern *ast) override;
- bool visit(AST::ArrayMemberExpression *ast) override;
- bool visit(AST::BinaryExpression *ast) override;
- bool visit(AST::CallExpression *ast) override;
- bool visit(AST::ConditionalExpression *ast) override;
- bool visit(AST::DeleteExpression *ast) override;
- bool visit(AST::FalseLiteral *ast) override;
- bool visit(AST::SuperLiteral *ast) override;
- bool visit(AST::FieldMemberExpression *ast) override;
- bool visit(AST::TaggedTemplate *ast) override;
- bool visit(AST::FunctionExpression *ast) override;
- bool visit(AST::IdentifierExpression *ast) override;
- bool visit(AST::NestedExpression *ast) override;
- bool visit(AST::NewExpression *ast) override;
- bool visit(AST::NewMemberExpression *ast) override;
- bool visit(AST::NotExpression *ast) override;
- bool visit(AST::NullExpression *ast) override;
- bool visit(AST::NumericLiteral *ast) override;
- bool visit(AST::ObjectPattern *ast) override;
- bool visit(AST::PostDecrementExpression *ast) override;
- bool visit(AST::PostIncrementExpression *ast) override;
- bool visit(AST::PreDecrementExpression *ast) override;
- bool visit(AST::PreIncrementExpression *ast) override;
- bool visit(AST::RegExpLiteral *ast) override;
- bool visit(AST::StringLiteral *ast) override;
- bool visit(AST::TemplateLiteral *ast) override;
- bool visit(AST::ThisExpression *ast) override;
- bool visit(AST::TildeExpression *ast) override;
- bool visit(AST::TrueLiteral *ast) override;
- bool visit(AST::TypeOfExpression *ast) override;
- bool visit(AST::UnaryMinusExpression *ast) override;
- bool visit(AST::UnaryPlusExpression *ast) override;
- bool visit(AST::VoidExpression *ast) override;
- bool visit(AST::FunctionDeclaration *ast) override;
- bool visit(AST::YieldExpression *ast) override;
- bool visit(AST::ClassExpression *ast) override;
- bool visit(AST::ClassDeclaration *ast) override;
+ bool visit(QQmlJS::AST::Expression *ast) override;
+ bool visit(QQmlJS::AST::ArrayPattern *ast) override;
+ bool visit(QQmlJS::AST::ArrayMemberExpression *ast) override;
+ bool visit(QQmlJS::AST::BinaryExpression *ast) override;
+ bool visit(QQmlJS::AST::CallExpression *ast) override;
+ bool visit(QQmlJS::AST::ConditionalExpression *ast) override;
+ bool visit(QQmlJS::AST::DeleteExpression *ast) override;
+ bool visit(QQmlJS::AST::FalseLiteral *ast) override;
+ bool visit(QQmlJS::AST::SuperLiteral *ast) override;
+ bool visit(QQmlJS::AST::FieldMemberExpression *ast) override;
+ bool visit(QQmlJS::AST::TaggedTemplate *ast) override;
+ bool visit(QQmlJS::AST::FunctionExpression *ast) override;
+ bool visit(QQmlJS::AST::IdentifierExpression *ast) override;
+ bool visit(QQmlJS::AST::NestedExpression *ast) override;
+ bool visit(QQmlJS::AST::NewExpression *ast) override;
+ bool visit(QQmlJS::AST::NewMemberExpression *ast) override;
+ bool visit(QQmlJS::AST::NotExpression *ast) override;
+ bool visit(QQmlJS::AST::NullExpression *ast) override;
+ bool visit(QQmlJS::AST::NumericLiteral *ast) override;
+ bool visit(QQmlJS::AST::ObjectPattern *ast) override;
+ bool visit(QQmlJS::AST::PostDecrementExpression *ast) override;
+ bool visit(QQmlJS::AST::PostIncrementExpression *ast) override;
+ bool visit(QQmlJS::AST::PreDecrementExpression *ast) override;
+ bool visit(QQmlJS::AST::PreIncrementExpression *ast) override;
+ bool visit(QQmlJS::AST::RegExpLiteral *ast) override;
+ bool visit(QQmlJS::AST::StringLiteral *ast) override;
+ bool visit(QQmlJS::AST::TemplateLiteral *ast) override;
+ bool visit(QQmlJS::AST::ThisExpression *ast) override;
+ bool visit(QQmlJS::AST::TildeExpression *ast) override;
+ bool visit(QQmlJS::AST::TrueLiteral *ast) override;
+ bool visit(QQmlJS::AST::TypeOfExpression *ast) override;
+ bool visit(QQmlJS::AST::UnaryMinusExpression *ast) override;
+ bool visit(QQmlJS::AST::UnaryPlusExpression *ast) override;
+ bool visit(QQmlJS::AST::VoidExpression *ast) override;
+ bool visit(QQmlJS::AST::FunctionDeclaration *ast) override;
+ bool visit(QQmlJS::AST::YieldExpression *ast) override;
+ bool visit(QQmlJS::AST::ClassExpression *ast) override;
+ bool visit(QQmlJS::AST::ClassDeclaration *ast) override;
// statements
- bool visit(AST::Block *ast) override;
- bool visit(AST::BreakStatement *ast) override;
- bool visit(AST::ContinueStatement *ast) override;
- bool visit(AST::DebuggerStatement *ast) override;
- bool visit(AST::DoWhileStatement *ast) override;
- bool visit(AST::EmptyStatement *ast) override;
- bool visit(AST::ExpressionStatement *ast) override;
- bool visit(AST::ForEachStatement *ast) override;
- bool visit(AST::ForStatement *ast) override;
- bool visit(AST::IfStatement *ast) override;
- bool visit(AST::LabelledStatement *ast) override;
- bool visit(AST::ReturnStatement *ast) override;
- bool visit(AST::SwitchStatement *ast) override;
- bool visit(AST::ThrowStatement *ast) override;
- bool visit(AST::TryStatement *ast) override;
- bool visit(AST::VariableStatement *ast) override;
- bool visit(AST::WhileStatement *ast) override;
- bool visit(AST::WithStatement *ast) override;
+ bool visit(QQmlJS::AST::Block *ast) override;
+ bool visit(QQmlJS::AST::BreakStatement *ast) override;
+ bool visit(QQmlJS::AST::ContinueStatement *ast) override;
+ bool visit(QQmlJS::AST::DebuggerStatement *ast) override;
+ bool visit(QQmlJS::AST::DoWhileStatement *ast) override;
+ bool visit(QQmlJS::AST::EmptyStatement *ast) override;
+ bool visit(QQmlJS::AST::ExpressionStatement *ast) override;
+ bool visit(QQmlJS::AST::ForEachStatement *ast) override;
+ bool visit(QQmlJS::AST::ForStatement *ast) override;
+ bool visit(QQmlJS::AST::IfStatement *ast) override;
+ bool visit(QQmlJS::AST::LabelledStatement *ast) override;
+ bool visit(QQmlJS::AST::ReturnStatement *ast) override;
+ bool visit(QQmlJS::AST::SwitchStatement *ast) override;
+ bool visit(QQmlJS::AST::ThrowStatement *ast) override;
+ bool visit(QQmlJS::AST::TryStatement *ast) override;
+ bool visit(QQmlJS::AST::VariableStatement *ast) override;
+ bool visit(QQmlJS::AST::WhileStatement *ast) override;
+ bool visit(QQmlJS::AST::WithStatement *ast) override;
// ui object members
- bool visit(AST::UiArrayBinding *ast) override;
- bool visit(AST::UiObjectBinding *ast) override;
- bool visit(AST::UiObjectDefinition *ast) override;
- bool visit(AST::UiPublicMember *ast) override;
- bool visit(AST::UiScriptBinding *ast) override;
- bool visit(AST::UiSourceElement *ast) override;
-
- bool throwSyntaxErrorOnEvalOrArgumentsInStrictMode(const Reference &r, const AST::SourceLocation &loc);
- virtual void throwSyntaxError(const AST::SourceLocation &loc, const QString &detail);
- virtual void throwReferenceError(const AST::SourceLocation &loc, const QString &detail);
+ bool visit(QQmlJS::AST::UiArrayBinding *ast) override;
+ bool visit(QQmlJS::AST::UiObjectBinding *ast) override;
+ bool visit(QQmlJS::AST::UiObjectDefinition *ast) override;
+ bool visit(QQmlJS::AST::UiPublicMember *ast) override;
+ bool visit(QQmlJS::AST::UiScriptBinding *ast) override;
+ bool visit(QQmlJS::AST::UiSourceElement *ast) override;
+
+ bool throwSyntaxErrorOnEvalOrArgumentsInStrictMode(const Reference &r,
+ const QQmlJS::AST::SourceLocation &loc);
+ virtual void throwSyntaxError(const QQmlJS::AST::SourceLocation &loc, const QString &detail);
+ virtual void throwReferenceError(const QQmlJS::AST::SourceLocation &loc, const QString &detail);
void throwRecursionDepthError() override
{
- throwSyntaxError(AST::SourceLocation(),
+ throwSyntaxError(QQmlJS::AST::SourceLocation(),
QStringLiteral("Maximum statement or expression depth exceeded"));
}
public:
- QList<DiagnosticMessage> errors() const;
-#ifndef V4_BOOTSTRAP
- QList<QQmlError> qmlErrors() const;
-#endif
+ enum ErrorType {
+ NoError,
+ SyntaxError,
+ ReferenceError
+ };
+
+ ErrorType errorType() const { return _errorType; }
+ bool hasError() const { return _errorType != NoError; }
+ QQmlJS::DiagnosticMessage error() const;
+ QUrl url() const;
Reference binopHelper(QSOperator::Op oper, Reference &left, Reference &right);
Reference jumpBinop(QSOperator::Op oper, Reference &left, Reference &right);
struct Arguments { int argc; int argv; bool hasSpread; };
- Arguments pushArgs(AST::ArgumentList *args);
+ Arguments pushArgs(QQmlJS::AST::ArgumentList *args);
void handleCall(Reference &base, Arguments calldata, int slotForFunction, int slotForThisObject);
- Arguments pushTemplateArgs(AST::TemplateLiteral *args);
- bool handleTaggedTemplate(Reference base, AST::TaggedTemplate *ast);
- void createTemplateObject(AST::TemplateLiteral *t);
+ Arguments pushTemplateArgs(QQmlJS::AST::TemplateLiteral *args);
+ bool handleTaggedTemplate(Reference base, QQmlJS::AST::TaggedTemplate *ast);
+ void createTemplateObject(QQmlJS::AST::TemplateLiteral *t);
void setUseFastLookups(bool b) { useFastLookups = b; }
- void handleTryCatch(AST::TryStatement *ast);
- void handleTryFinally(AST::TryStatement *ast);
+ void handleTryCatch(QQmlJS::AST::TryStatement *ast);
+ void handleTryFinally(QQmlJS::AST::TryStatement *ast);
- Reference referenceForName(const QString &name, bool lhs, const QQmlJS::AST::SourceLocation &accessLocation = QQmlJS::AST::SourceLocation());
+ Reference referenceForName(
+ const QString &name, bool lhs,
+ const QQmlJS::AST::SourceLocation &accessLocation = QQmlJS::AST::SourceLocation());
- QQmlRefPointer<QV4::CompiledData::CompilationUnit> generateCompilationUnit(bool generateUnitData = true);
- static QQmlRefPointer<QV4::CompiledData::CompilationUnit> createUnitForLoading();
+ QV4::CompiledData::CompilationUnit generateCompilationUnit(bool generateUnitData = true);
+ static QV4::CompiledData::CompilationUnit compileModule(
+ bool debugMode, const QString &url, const QString &sourceCode,
+ const QDateTime &sourceTimeStamp, QList<QQmlJS::DiagnosticMessage> *diagnostics);
Context *currentContext() const { return _context; }
BytecodeGenerator *generator() const { return bytecodeGenerator; }
@@ -751,7 +764,7 @@ protected:
int _returnAddress;
Context *_context;
Context *_functionContext = nullptr;
- AST::LabelledStatement *_labelledStatement;
+ QQmlJS::AST::LabelledStatement *_labelledStatement;
QV4::Compiler::JSUnitGenerator *jsUnitGenerator;
BytecodeGenerator *bytecodeGenerator = nullptr;
Moth::BytecodeGenerator::Label *_returnLabel = nullptr;
@@ -767,8 +780,8 @@ protected:
ControlFlow *controlFlow = nullptr;
bool _fileNameIsUrl;
- bool hasError;
- QList<QQmlJS::DiagnosticMessage> _errors;
+ ErrorType _errorType = NoError;
+ QQmlJS::DiagnosticMessage _error;
class TailCallBlocker
{
@@ -795,8 +808,10 @@ protected:
};
private:
- VolatileMemoryLocations scanVolatileMemoryLocations(AST::Node *ast);
- void handleConstruct(const Reference &base, AST::ArgumentList *args);
+ VolatileMemoryLocations scanVolatileMemoryLocations(QQmlJS::AST::Node *ast);
+ void handleConstruct(const Reference &base, QQmlJS::AST::ArgumentList *args);
+ void throwError(ErrorType errorType, const QQmlJS::AST::SourceLocation &loc,
+ const QString &detail);
};
}
diff --git a/src/qml/compiler/qv4compilationunitmapper.cpp b/src/qml/compiler/qv4compilationunitmapper.cpp
deleted file mode 100644
index 350f6f9485..0000000000
--- a/src/qml/compiler/qv4compilationunitmapper.cpp
+++ /dev/null
@@ -1,62 +0,0 @@
-/****************************************************************************
-**
-** 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$
-**
-****************************************************************************/
-
-#include "qv4compilationunitmapper_p.h"
-
-#include "qv4compileddata_p.h"
-#include <QFileInfo>
-#include <QDateTime>
-#include <QCoreApplication>
-
-QT_BEGIN_NAMESPACE
-
-using namespace QV4;
-
-CompilationUnitMapper::CompilationUnitMapper()
- : dataPtr(nullptr)
-{
-
-}
-
-CompilationUnitMapper::~CompilationUnitMapper()
-{
- close();
-}
-
-QT_END_NAMESPACE
diff --git a/src/qml/compiler/qv4compilationunitmapper_unix.cpp b/src/qml/compiler/qv4compilationunitmapper_unix.cpp
deleted file mode 100644
index 6768bc9596..0000000000
--- a/src/qml/compiler/qv4compilationunitmapper_unix.cpp
+++ /dev/null
@@ -1,108 +0,0 @@
-/****************************************************************************
-**
-** 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$
-**
-****************************************************************************/
-
-#include "qv4compilationunitmapper_p.h"
-
-#include <sys/mman.h>
-#include <functional>
-#include <private/qcore_unix_p.h>
-#include <QScopeGuard>
-#include <QDateTime>
-
-#include "qv4compileddata_p.h"
-
-QT_BEGIN_NAMESPACE
-
-using namespace QV4;
-
-CompiledData::Unit *CompilationUnitMapper::open(const QString &cacheFileName, const QDateTime &sourceTimeStamp, QString *errorString)
-{
- close();
-
- int fd = qt_safe_open(QFile::encodeName(cacheFileName).constData(), O_RDONLY);
- if (fd == -1) {
- *errorString = qt_error_string(errno);
- return nullptr;
- }
-
- auto cleanup = qScopeGuard([fd]{
- qt_safe_close(fd) ;
- });
-
- CompiledData::Unit header;
- qint64 bytesRead = qt_safe_read(fd, reinterpret_cast<char *>(&header), sizeof(header));
-
- if (bytesRead != sizeof(header)) {
- *errorString = QStringLiteral("File too small for the header fields");
- return nullptr;
- }
-
- if (!header.verifyHeader(sourceTimeStamp, errorString))
- return nullptr;
-
- // Data structure and qt version matched, so now we can access the rest of the file safely.
-
- length = static_cast<size_t>(lseek(fd, 0, SEEK_END));
-
- void *ptr = mmap(nullptr, length, PROT_READ, MAP_SHARED, fd, /*offset*/0);
- if (ptr == MAP_FAILED) {
- *errorString = qt_error_string(errno);
- return nullptr;
- }
- dataPtr = ptr;
-
- return reinterpret_cast<CompiledData::Unit*>(dataPtr);
-}
-
-void CompilationUnitMapper::close()
-{
- // Do not unmap the data here.
- if (dataPtr != nullptr) {
- // Do not unmap cache files that are built with the StaticData flag. That's the majority of
- // them and it's necessary to benefit from the QString literal optimization. There might
- // still be QString instances around that point into that memory area. The memory is backed
- // on the disk, so the kernel is free to release the pages and all that remains is the
- // address space allocation.
- if (!(reinterpret_cast<CompiledData::Unit*>(dataPtr)->flags & CompiledData::Unit::StaticData))
- munmap(dataPtr, length);
- }
- dataPtr = nullptr;
-}
-
-QT_END_NAMESPACE
diff --git a/src/qml/compiler/qv4compilationunitmapper_win.cpp b/src/qml/compiler/qv4compilationunitmapper_win.cpp
deleted file mode 100644
index 779c1288fe..0000000000
--- a/src/qml/compiler/qv4compilationunitmapper_win.cpp
+++ /dev/null
@@ -1,128 +0,0 @@
-/****************************************************************************
-**
-** 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$
-**
-****************************************************************************/
-
-#include "qv4compilationunitmapper_p.h"
-
-#include "qv4compileddata_p.h"
-#include <QScopeGuard>
-#include <QFileInfo>
-#include <QDateTime>
-#include <qt_windows.h>
-
-QT_BEGIN_NAMESPACE
-
-using namespace QV4;
-
-CompiledData::Unit *CompilationUnitMapper::open(const QString &cacheFileName, const QDateTime &sourceTimeStamp, QString *errorString)
-{
- close();
-
- // ### TODO: fix up file encoding/normalization/unc handling once QFileSystemEntry
- // is exported from QtCore.
- HANDLE handle =
-#if defined(Q_OS_WINRT)
- CreateFile2(reinterpret_cast<const wchar_t*>(cacheFileName.constData()),
- GENERIC_READ | GENERIC_EXECUTE, FILE_SHARE_READ,
- OPEN_EXISTING, nullptr);
-#else
- CreateFile(reinterpret_cast<const wchar_t*>(cacheFileName.constData()),
- GENERIC_READ | GENERIC_EXECUTE, FILE_SHARE_READ,
- nullptr, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL,
- nullptr);
-#endif
- if (handle == INVALID_HANDLE_VALUE) {
- *errorString = qt_error_string(GetLastError());
- return nullptr;
- }
-
- auto fileHandleCleanup = qScopeGuard([handle]{
- CloseHandle(handle);
- });
-
- CompiledData::Unit header;
- DWORD bytesRead;
- if (!ReadFile(handle, reinterpret_cast<char *>(&header), sizeof(header), &bytesRead, nullptr)) {
- *errorString = qt_error_string(GetLastError());
- return nullptr;
- }
-
- if (bytesRead != sizeof(header)) {
- *errorString = QStringLiteral("File too small for the header fields");
- return nullptr;
- }
-
- if (!header.verifyHeader(sourceTimeStamp, errorString))
- return nullptr;
-
- // Data structure and qt version matched, so now we can access the rest of the file safely.
-
- HANDLE fileMappingHandle = CreateFileMapping(handle, 0, PAGE_READONLY, 0, 0, 0);
- if (!fileMappingHandle) {
- *errorString = qt_error_string(GetLastError());
- return nullptr;
- }
-
- auto mappingCleanup = qScopeGuard([fileMappingHandle]{
- CloseHandle(fileMappingHandle);
- });
-
- dataPtr = MapViewOfFile(fileMappingHandle, FILE_MAP_READ, 0, 0, 0);
- if (!dataPtr) {
- *errorString = qt_error_string(GetLastError());
- return nullptr;
- }
-
- return reinterpret_cast<CompiledData::Unit*>(dataPtr);
-}
-
-void CompilationUnitMapper::close()
-{
- if (dataPtr != nullptr) {
- // Do not unmap cache files that are built with the StaticData flag. That's the majority of
- // them and it's necessary to benefit from the QString literal optimization. There might
- // still be QString instances around that point into that memory area. The memory is backed
- // on the disk, so the kernel is free to release the pages and all that remains is the
- // address space allocation.
- if (!(reinterpret_cast<CompiledData::Unit*>(dataPtr)->flags & CompiledData::Unit::StaticData))
- UnmapViewOfFile(dataPtr);
- }
- dataPtr = nullptr;
-}
-
-QT_END_NAMESPACE
diff --git a/src/qml/compiler/qv4compileddata.cpp b/src/qml/compiler/qv4compileddata.cpp
deleted file mode 100644
index c0ce125741..0000000000
--- a/src/qml/compiler/qv4compileddata.cpp
+++ /dev/null
@@ -1,1030 +0,0 @@
-/****************************************************************************
-**
-** 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$
-**
-****************************************************************************/
-
-#include "qv4compileddata_p.h"
-#include <private/qv4value_p.h>
-#ifndef V4_BOOTSTRAP
-#include <private/qv4engine_p.h>
-#include <private/qv4function_p.h>
-#include <private/qv4objectproto_p.h>
-#include <private/qv4lookup_p.h>
-#include <private/qv4regexpobject_p.h>
-#include <private/qv4regexp_p.h>
-#include <private/qqmlpropertycache_p.h>
-#include <private/qqmltypeloader_p.h>
-#include <private/qqmlengine_p.h>
-#include <private/qv4vme_moth_p.h>
-#include <private/qv4module_p.h>
-#include <private/qv4qobjectwrapper_p.h>
-#include <private/qqmlvaluetypewrapper_p.h>
-#include "qv4compilationunitmapper_p.h"
-#include <QQmlPropertyMap>
-#include <QDateTime>
-#include <QFile>
-#include <QFileInfo>
-#include <QScopedValueRollback>
-#include <QStandardPaths>
-#include <QDir>
-#include <private/qv4identifiertable_p.h>
-#endif
-#include <private/qqmlirbuilder_p.h>
-#include <QCoreApplication>
-#include <QCryptographicHash>
-#include <QSaveFile>
-#include <QScopeGuard>
-
-// generated by qmake:
-#include "qml_compile_hash_p.h"
-
-#include <algorithm>
-
-QT_BEGIN_NAMESPACE
-
-namespace QV4 {
-
-namespace CompiledData {
-
-#if defined(QML_COMPILE_HASH)
-# ifdef Q_OS_LINUX
-// Place on a separate section on Linux so it's easier to check from outside
-// what the hash version is.
-__attribute__((section(".qml_compile_hash")))
-# endif
-const char qml_compile_hash[48 + 1] = QML_COMPILE_HASH;
-static_assert(sizeof(Unit::libraryVersionHash) >= QML_COMPILE_HASH_LENGTH + 1, "Compile hash length exceeds reserved size in data structure. Please adjust and bump the format version");
-#else
-# error "QML_COMPILE_HASH must be defined for the build of QtDeclarative to ensure version checking for cache files"
-#endif
-
-
-CompilationUnit::CompilationUnit(const Unit *unitData, const QString &fileName, const QString &finalUrlString)
-{
- setUnitData(unitData, nullptr, fileName, finalUrlString);
-}
-
-CompilationUnit::~CompilationUnit()
-{
-#ifndef V4_BOOTSTRAP
- unlink();
-#endif
-
- if (data) {
- if (data->qmlUnit() != qmlData)
- free(const_cast<QmlUnit *>(qmlData));
- qmlData = nullptr;
-
-#ifndef V4_BOOTSTRAP
- if (!(data->flags & QV4::CompiledData::Unit::StaticData))
- free(const_cast<Unit *>(data));
-#else
- // Unconditionally free the memory. In the dev tools we create units that have
- // the flag set and will be saved to disk, so intended to persist later.
- free(const_cast<Unit *>(data));
-#endif
- }
- data = nullptr;
-#if Q_BYTE_ORDER == Q_BIG_ENDIAN
- delete [] constants;
- constants = nullptr;
-#endif
-
- delete [] imports;
- imports = nullptr;
-}
-#ifndef V4_BOOTSTRAP
-
-QString CompilationUnit::localCacheFilePath(const QUrl &url)
-{
- const QString localSourcePath = QQmlFile::urlToLocalFileOrQrc(url);
- const QString cacheFileSuffix = QFileInfo(localSourcePath + QLatin1Char('c')).completeSuffix();
- QCryptographicHash fileNameHash(QCryptographicHash::Sha1);
- fileNameHash.addData(localSourcePath.toUtf8());
- QString directory = QStandardPaths::writableLocation(QStandardPaths::CacheLocation) + QLatin1String("/qmlcache/");
- QDir::root().mkpath(directory);
- return directory + QString::fromUtf8(fileNameHash.result().toHex()) + QLatin1Char('.') + cacheFileSuffix;
-}
-
-QV4::Function *CompilationUnit::linkToEngine(ExecutionEngine *engine)
-{
- this->engine = engine;
- engine->compilationUnits.insert(this);
-
- Q_ASSERT(!runtimeStrings);
- Q_ASSERT(data);
- const quint32 stringCount = totalStringCount();
- runtimeStrings = (QV4::Heap::String **)malloc(stringCount * sizeof(QV4::Heap::String*));
- // memset the strings to 0 in case a GC run happens while we're within the loop below
- memset(runtimeStrings, 0, stringCount * sizeof(QV4::Heap::String*));
- for (uint i = 0; i < stringCount; ++i)
- runtimeStrings[i] = engine->newString(stringAt(i));
-
- runtimeRegularExpressions = new QV4::Value[data->regexpTableSize];
- // memset the regexps to 0 in case a GC run happens while we're within the loop below
- memset(runtimeRegularExpressions, 0, data->regexpTableSize * sizeof(QV4::Value));
- for (uint i = 0; i < data->regexpTableSize; ++i) {
- const CompiledData::RegExp *re = data->regexpAt(i);
- uint f = re->flags;
- const CompiledData::RegExp::Flags flags = static_cast<CompiledData::RegExp::Flags>(f);
- runtimeRegularExpressions[i] = QV4::RegExp::create(engine, stringAt(re->stringIndex), flags);
- }
-
- if (data->lookupTableSize) {
- runtimeLookups = new QV4::Lookup[data->lookupTableSize];
- memset(runtimeLookups, 0, data->lookupTableSize * sizeof(QV4::Lookup));
- const CompiledData::Lookup *compiledLookups = data->lookupTable();
- for (uint i = 0; i < data->lookupTableSize; ++i) {
- QV4::Lookup *l = runtimeLookups + i;
-
- Lookup::Type type = Lookup::Type(uint(compiledLookups[i].type_and_flags));
- if (type == CompiledData::Lookup::Type_Getter)
- l->getter = QV4::Lookup::getterGeneric;
- else if (type == CompiledData::Lookup::Type_Setter)
- l->setter = QV4::Lookup::setterGeneric;
- else if (type == CompiledData::Lookup::Type_GlobalGetter)
- l->globalGetter = QV4::Lookup::globalGetterGeneric;
- else if (type == CompiledData::Lookup::Type_QmlContextPropertyGetter)
- l->qmlContextPropertyGetter = QQmlContextWrapper::resolveQmlContextPropertyLookupGetter;
- l->nameIndex = compiledLookups[i].nameIndex;
- }
- }
-
- if (data->jsClassTableSize) {
- runtimeClasses = (QV4::Heap::InternalClass **)malloc(data->jsClassTableSize * sizeof(QV4::Heap::InternalClass *));
- // memset the regexps to 0 in case a GC run happens while we're within the loop below
- memset(runtimeClasses, 0, data->jsClassTableSize * sizeof(QV4::Heap::InternalClass *));
- for (uint i = 0; i < data->jsClassTableSize; ++i) {
- int memberCount = 0;
- const CompiledData::JSClassMember *member = data->jsClassAt(i, &memberCount);
- runtimeClasses[i] = engine->internalClasses(QV4::ExecutionEngine::Class_Object);
- for (int j = 0; j < memberCount; ++j, ++member)
- runtimeClasses[i] = runtimeClasses[i]->addMember(engine->identifierTable->asPropertyKey(runtimeStrings[member->nameOffset]), member->isAccessor ? QV4::Attr_Accessor : QV4::Attr_Data);
- }
- }
-
- runtimeFunctions.resize(data->functionTableSize);
- for (int i = 0 ;i < runtimeFunctions.size(); ++i) {
- const QV4::CompiledData::Function *compiledFunction = data->functionAt(i);
- runtimeFunctions[i] = QV4::Function::create(engine, this, compiledFunction);
- }
-
- Scope scope(engine);
- Scoped<InternalClass> ic(scope);
-
- runtimeBlocks.resize(data->blockTableSize);
- for (int i = 0 ;i < runtimeBlocks.size(); ++i) {
- const QV4::CompiledData::Block *compiledBlock = data->blockAt(i);
- ic = engine->internalClasses(EngineBase::Class_CallContext);
-
- // first locals
- const quint32_le *localsIndices = compiledBlock->localsTable();
- for (quint32 j = 0; j < compiledBlock->nLocals; ++j)
- ic = ic->addMember(engine->identifierTable->asPropertyKey(runtimeStrings[localsIndices[j]]), Attr_NotConfigurable);
- runtimeBlocks[i] = ic->d();
- }
-
- static const bool showCode = qEnvironmentVariableIsSet("QV4_SHOW_BYTECODE");
- if (showCode) {
- qDebug() << "=== Constant table";
- Moth::dumpConstantTable(constants, data->constantTableSize);
- qDebug() << "=== String table";
- for (uint i = 0, end = totalStringCount(); i < end; ++i)
- qDebug() << " " << i << ":" << runtimeStrings[i]->toQString();
- qDebug() << "=== Closure table";
- for (uint i = 0; i < data->functionTableSize; ++i)
- qDebug() << " " << i << ":" << runtimeFunctions[i]->name()->toQString();
- qDebug() << "root function at index " << (data->indexOfRootFunction != -1 ? data->indexOfRootFunction : 0);
- }
-
- if (data->indexOfRootFunction != -1)
- return runtimeFunctions[data->indexOfRootFunction];
- else
- return nullptr;
-}
-
-Heap::Object *CompilationUnit::templateObjectAt(int index) const
-{
- Q_ASSERT(index < int(data->templateObjectTableSize));
- if (!templateObjects.size())
- templateObjects.resize(data->templateObjectTableSize);
- Heap::Object *o = templateObjects.at(index);
- if (o)
- return o;
-
- // create the template object
- Scope scope(engine);
- const CompiledData::TemplateObject *t = data->templateObjectAt(index);
- Scoped<ArrayObject> a(scope, engine->newArrayObject(t->size));
- Scoped<ArrayObject> raw(scope, engine->newArrayObject(t->size));
- ScopedValue s(scope);
- for (uint i = 0; i < t->size; ++i) {
- s = runtimeStrings[t->stringIndexAt(i)];
- a->arraySet(i, s);
- s = runtimeStrings[t->rawStringIndexAt(i)];
- raw->arraySet(i, s);
- }
-
- ObjectPrototype::method_freeze(engine->functionCtor(), nullptr, raw, 1);
- a->defineReadonlyProperty(QStringLiteral("raw"), raw);
- ObjectPrototype::method_freeze(engine->functionCtor(), nullptr, a, 1);
-
- templateObjects[index] = a->objectValue()->d();
- return templateObjects.at(index);
-}
-
-void CompilationUnit::unlink()
-{
- if (engine)
- nextCompilationUnit.remove();
-
- if (isRegisteredWithEngine) {
- Q_ASSERT(data && propertyCaches.count() > 0 && propertyCaches.at(/*root object*/0));
- if (qmlEngine)
- qmlEngine->unregisterInternalCompositeType(this);
- QQmlMetaType::unregisterInternalCompositeType(this);
- isRegisteredWithEngine = false;
- }
-
- propertyCaches.clear();
-
- if (runtimeLookups) {
- for (uint i = 0; i < data->lookupTableSize; ++i) {
- QV4::Lookup &l = runtimeLookups[i];
- if (l.getter == QV4::QObjectWrapper::lookupGetter) {
- if (QQmlPropertyCache *pc = l.qobjectLookup.propertyCache)
- pc->release();
- } else if (l.getter == QQmlValueTypeWrapper::lookupGetter) {
- if (QQmlPropertyCache *pc = l.qgadgetLookup.propertyCache)
- pc->release();
- }
-
- if (l.qmlContextPropertyGetter == QQmlContextWrapper::lookupScopeObjectProperty) {
- if (QQmlPropertyCache *pc = l.qobjectLookup.propertyCache)
- pc->release();
- }
- }
- }
-
- dependentScripts.clear();
-
- typeNameCache = nullptr;
-
- qDeleteAll(resolvedTypes);
- resolvedTypes.clear();
-
- engine = nullptr;
- qmlEngine = nullptr;
- free(runtimeStrings);
- runtimeStrings = nullptr;
- delete [] runtimeLookups;
- runtimeLookups = nullptr;
- delete [] runtimeRegularExpressions;
- runtimeRegularExpressions = nullptr;
- free(runtimeClasses);
- runtimeClasses = nullptr;
- for (QV4::Function *f : qAsConst(runtimeFunctions))
- f->destroy();
- runtimeFunctions.clear();
-}
-
-void CompilationUnit::markObjects(QV4::MarkStack *markStack)
-{
- if (runtimeStrings) {
- for (uint i = 0, end = totalStringCount(); i < end; ++i)
- if (runtimeStrings[i])
- runtimeStrings[i]->mark(markStack);
- }
- if (runtimeRegularExpressions) {
- for (uint i = 0; i < data->regexpTableSize; ++i)
- runtimeRegularExpressions[i].mark(markStack);
- }
- if (runtimeClasses) {
- for (uint i = 0; i < data->jsClassTableSize; ++i)
- if (runtimeClasses[i])
- runtimeClasses[i]->mark(markStack);
- }
- for (QV4::Function *f : qAsConst(runtimeFunctions))
- if (f && f->internalClass)
- f->internalClass->mark(markStack);
- for (QV4::Heap::InternalClass *c : qAsConst(runtimeBlocks))
- if (c)
- c->mark(markStack);
-
- for (QV4::Heap::Object *o : qAsConst(templateObjects))
- if (o)
- o->mark(markStack);
-
- if (runtimeLookups) {
- for (uint i = 0; i < data->lookupTableSize; ++i)
- runtimeLookups[i].markObjects(markStack);
- }
-
- if (m_module)
- m_module->mark(markStack);
-}
-
-IdentifierHash CompilationUnit::createNamedObjectsPerComponent(int componentObjectIndex)
-{
- IdentifierHash namedObjectCache(engine);
- const CompiledData::Object *component = objectAt(componentObjectIndex);
- const quint32_le *namedObjectIndexPtr = component->namedObjectsInComponentTable();
- for (quint32 i = 0; i < component->nNamedObjectsInComponent; ++i, ++namedObjectIndexPtr) {
- const CompiledData::Object *namedObject = objectAt(*namedObjectIndexPtr);
- namedObjectCache.add(runtimeStrings[namedObject->idNameIndex], namedObject->id);
- }
- return *namedObjectsPerComponentCache.insert(componentObjectIndex, namedObjectCache);
-}
-
-void CompilationUnit::finalizeCompositeType(QQmlEnginePrivate *qmlEngine)
-{
- this->qmlEngine = qmlEngine;
-
- // Add to type registry of composites
- if (propertyCaches.needsVMEMetaObject(/*root object*/0)) {
- QQmlMetaType::registerInternalCompositeType(this);
- qmlEngine->registerInternalCompositeType(this);
- } else {
- const QV4::CompiledData::Object *obj = objectAt(/*root object*/0);
- auto *typeRef = resolvedTypes.value(obj->inheritedTypeNameIndex);
- Q_ASSERT(typeRef);
- if (typeRef->compilationUnit) {
- metaTypeId = typeRef->compilationUnit->metaTypeId;
- listMetaTypeId = typeRef->compilationUnit->listMetaTypeId;
- } else {
- metaTypeId = typeRef->type.typeId();
- listMetaTypeId = typeRef->type.qListTypeId();
- }
- }
-
- // Collect some data for instantiation later.
- int bindingCount = 0;
- int parserStatusCount = 0;
- int objectCount = 0;
- for (quint32 i = 0, count = this->objectCount(); i < count; ++i) {
- const QV4::CompiledData::Object *obj = objectAt(i);
- bindingCount += obj->nBindings;
- if (auto *typeRef = resolvedTypes.value(obj->inheritedTypeNameIndex)) {
- if (typeRef->type.isValid()) {
- if (typeRef->type.parserStatusCast() != -1)
- ++parserStatusCount;
- }
- ++objectCount;
- if (typeRef->compilationUnit) {
- bindingCount += typeRef->compilationUnit->totalBindingsCount;
- parserStatusCount += typeRef->compilationUnit->totalParserStatusCount;
- objectCount += typeRef->compilationUnit->totalObjectCount;
- }
- }
- }
-
- totalBindingsCount = bindingCount;
- totalParserStatusCount = parserStatusCount;
- totalObjectCount = objectCount;
-}
-
-bool CompilationUnit::verifyChecksum(const DependentTypesHasher &dependencyHasher) const
-{
- if (!dependencyHasher) {
- for (size_t i = 0; i < sizeof(data->dependencyMD5Checksum); ++i) {
- if (data->dependencyMD5Checksum[i] != 0)
- return false;
- }
- return true;
- }
- QCryptographicHash hash(QCryptographicHash::Md5);
- if (!dependencyHasher(&hash))
- return false;
- QByteArray checksum = hash.result();
- Q_ASSERT(checksum.size() == sizeof(data->dependencyMD5Checksum));
- return memcmp(data->dependencyMD5Checksum, checksum.constData(),
- sizeof(data->dependencyMD5Checksum)) == 0;
-}
-
-QStringList CompilationUnit::moduleRequests() const
-{
- QStringList requests;
- requests.reserve(data->moduleRequestTableSize);
- for (uint i = 0; i < data->moduleRequestTableSize; ++i)
- requests << stringAt(data->moduleRequestTable()[i]);
- return requests;
-}
-
-Heap::Module *CompilationUnit::instantiate(ExecutionEngine *engine)
-{
- if (isESModule() && m_module)
- return m_module;
-
- if (data->indexOfRootFunction < 0)
- return nullptr;
-
- if (!this->engine)
- linkToEngine(engine);
-
- Scope scope(engine);
- Scoped<Module> module(scope, engine->memoryManager->allocate<Module>(engine, this));
-
- if (isESModule())
- m_module = module->d();
-
- for (const QString &request: moduleRequests()) {
- auto dependentModuleUnit = engine->loadModule(QUrl(request), this);
- if (engine->hasException)
- return nullptr;
- dependentModuleUnit->instantiate(engine);
- }
-
- ScopedString importName(scope);
-
- const uint importCount = data->importEntryTableSize;
- if (importCount > 0) {
- imports = new const Value *[importCount];
- memset(imports, 0, importCount * sizeof(Value *));
- }
- for (uint i = 0; i < importCount; ++i) {
- const CompiledData::ImportEntry &entry = data->importEntryTable()[i];
- auto dependentModuleUnit = engine->loadModule(QUrl(stringAt(entry.moduleRequest)), this);
- importName = runtimeStrings[entry.importName];
- const Value *valuePtr = dependentModuleUnit->resolveExport(importName);
- if (!valuePtr) {
- QString referenceErrorMessage = QStringLiteral("Unable to resolve import reference ");
- referenceErrorMessage += importName->toQString();
- engine->throwReferenceError(referenceErrorMessage, fileName(), entry.location.line, entry.location.column);
- return nullptr;
- }
- imports[i] = valuePtr;
- }
-
- for (uint i = 0; i < data->indirectExportEntryTableSize; ++i) {
- const CompiledData::ExportEntry &entry = data->indirectExportEntryTable()[i];
- auto dependentModuleUnit = engine->loadModule(QUrl(stringAt(entry.moduleRequest)), this);
- if (!dependentModuleUnit)
- return nullptr;
-
- ScopedString importName(scope, runtimeStrings[entry.importName]);
- if (!dependentModuleUnit->resolveExport(importName)) {
- QString referenceErrorMessage = QStringLiteral("Unable to resolve re-export reference ");
- referenceErrorMessage += importName->toQString();
- engine->throwReferenceError(referenceErrorMessage, fileName(), entry.location.line, entry.location.column);
- return nullptr;
- }
- }
-
- return module->d();
-}
-
-const Value *CompilationUnit::resolveExport(QV4::String *exportName)
-{
- QVector<ResolveSetEntry> resolveSet;
- return resolveExportRecursively(exportName, &resolveSet);
-}
-
-QStringList CompilationUnit::exportedNames() const
-{
- QStringList names;
- QVector<const CompiledData::CompilationUnit*> exportNameSet;
- getExportedNamesRecursively(&names, &exportNameSet);
- names.sort();
- auto last = std::unique(names.begin(), names.end());
- names.erase(last, names.end());
- return names;
-}
-
-const Value *CompilationUnit::resolveExportRecursively(QV4::String *exportName, QVector<ResolveSetEntry> *resolveSet)
-{
- if (!m_module)
- return nullptr;
-
- for (const auto &entry: *resolveSet)
- if (entry.module == this && entry.exportName->isEqualTo(exportName))
- return nullptr;
-
- (*resolveSet) << ResolveSetEntry(this, exportName);
-
- if (exportName->toQString() == QLatin1String("*"))
- return &m_module->self;
-
- Scope scope(engine);
-
- if (auto localExport = lookupNameInExportTable(data->localExportEntryTable(), data->localExportEntryTableSize, exportName)) {
- ScopedString localName(scope, runtimeStrings[localExport->localName]);
- uint index = m_module->scope->internalClass->indexOfValueOrGetter(localName->toPropertyKey());
- if (index == UINT_MAX)
- return nullptr;
- if (index >= m_module->scope->locals.size)
- return imports[index - m_module->scope->locals.size];
- return &m_module->scope->locals[index];
- }
-
- if (auto indirectExport = lookupNameInExportTable(data->indirectExportEntryTable(), data->indirectExportEntryTableSize, exportName)) {
- auto dependentModuleUnit = engine->loadModule(QUrl(stringAt(indirectExport->moduleRequest)), this);
- if (!dependentModuleUnit)
- return nullptr;
- ScopedString importName(scope, runtimeStrings[indirectExport->importName]);
- return dependentModuleUnit->resolveExportRecursively(importName, resolveSet);
- }
-
-
- if (exportName->toQString() == QLatin1String("default"))
- return nullptr;
-
- const Value *starResolution = nullptr;
-
- for (uint i = 0; i < data->starExportEntryTableSize; ++i) {
- const CompiledData::ExportEntry &entry = data->starExportEntryTable()[i];
- auto dependentModuleUnit = engine->loadModule(QUrl(stringAt(entry.moduleRequest)), this);
- if (!dependentModuleUnit)
- return nullptr;
-
- const Value *resolution = dependentModuleUnit->resolveExportRecursively(exportName, resolveSet);
- // ### handle ambiguous
- if (resolution) {
- if (!starResolution) {
- starResolution = resolution;
- continue;
- }
- if (resolution != starResolution)
- return nullptr;
- }
- }
-
- return starResolution;
-}
-
-const ExportEntry *CompilationUnit::lookupNameInExportTable(const ExportEntry *firstExportEntry, int tableSize, QV4::String *name) const
-{
- const CompiledData::ExportEntry *lastExportEntry = firstExportEntry + tableSize;
- auto matchingExport = std::lower_bound(firstExportEntry, lastExportEntry, name, [this](const CompiledData::ExportEntry &lhs, QV4::String *name) {
- return stringAt(lhs.exportName) < name->toQString();
- });
- if (matchingExport == lastExportEntry || stringAt(matchingExport->exportName) != name->toQString())
- return nullptr;
- return matchingExport;
-}
-
-void CompilationUnit::getExportedNamesRecursively(QStringList *names, QVector<const CompilationUnit*> *exportNameSet, bool includeDefaultExport) const
-{
- if (exportNameSet->contains(this))
- return;
- exportNameSet->append(this);
-
- const auto append = [names, includeDefaultExport](const QString &name) {
- if (!includeDefaultExport && name == QLatin1String("default"))
- return;
- names->append(name);
- };
-
- for (uint i = 0; i < data->localExportEntryTableSize; ++i) {
- const CompiledData::ExportEntry &entry = data->localExportEntryTable()[i];
- append(stringAt(entry.exportName));
- }
-
- for (uint i = 0; i < data->indirectExportEntryTableSize; ++i) {
- const CompiledData::ExportEntry &entry = data->indirectExportEntryTable()[i];
- append(stringAt(entry.exportName));
- }
-
- for (uint i = 0; i < data->starExportEntryTableSize; ++i) {
- const CompiledData::ExportEntry &entry = data->starExportEntryTable()[i];
- auto dependentModuleUnit = engine->loadModule(QUrl(stringAt(entry.moduleRequest)), this);
- if (!dependentModuleUnit)
- return;
- dependentModuleUnit->getExportedNamesRecursively(names, exportNameSet, /*includeDefaultExport*/false);
- }
-}
-
-void CompilationUnit::evaluate()
-{
- QV4::Scope scope(engine);
- QV4::Scoped<Module> module(scope, m_module);
- module->evaluate();
-}
-
-void CompilationUnit::evaluateModuleRequests()
-{
- for (const QString &request: moduleRequests()) {
- auto dependentModuleUnit = engine->loadModule(QUrl(request), this);
- if (engine->hasException)
- return;
- dependentModuleUnit->evaluate();
- if (engine->hasException)
- return;
- }
-}
-
-bool CompilationUnit::loadFromDisk(const QUrl &url, const QDateTime &sourceTimeStamp, QString *errorString)
-{
- if (!QQmlFile::isLocalFile(url)) {
- *errorString = QStringLiteral("File has to be a local file.");
- return false;
- }
-
- const QString sourcePath = QQmlFile::urlToLocalFileOrQrc(url);
- QScopedPointer<CompilationUnitMapper> cacheFile(new CompilationUnitMapper());
-
- const QStringList cachePaths = { sourcePath + QLatin1Char('c'), localCacheFilePath(url) };
- for (const QString &cachePath : cachePaths) {
- CompiledData::Unit *mappedUnit = cacheFile->open(cachePath, sourceTimeStamp, errorString);
- if (!mappedUnit)
- continue;
-
- const Unit * const oldDataPtr = (data && !(data->flags & QV4::CompiledData::Unit::StaticData)) ? data : nullptr;
- const Unit *oldData = data;
- auto dataPtrRevert = qScopeGuard([this, oldData](){
- setUnitData(oldData);
- });
- setUnitData(mappedUnit);
-
- if (data->sourceFileIndex != 0 && sourcePath != QQmlFile::urlToLocalFileOrQrc(stringAt(data->sourceFileIndex))) {
- *errorString = QStringLiteral("QML source file has moved to a different location.");
- continue;
- }
-
- dataPtrRevert.dismiss();
- free(const_cast<Unit*>(oldDataPtr));
- backingFile.reset(cacheFile.take());
- return true;
- }
-
- return false;
-}
-
-#endif // V4_BOOTSTRAP
-
-#if defined(V4_BOOTSTRAP)
-bool CompilationUnit::saveToDisk(const QString &outputFileName, QString *errorString)
-#else
-bool CompilationUnit::saveToDisk(const QUrl &unitUrl, QString *errorString)
-#endif
-{
- errorString->clear();
-
-#if !defined(V4_BOOTSTRAP)
- if (data->sourceTimeStamp == 0) {
- *errorString = QStringLiteral("Missing time stamp for source file");
- return false;
- }
-
- if (!QQmlFile::isLocalFile(unitUrl)) {
- *errorString = QStringLiteral("File has to be a local file.");
- return false;
- }
- const QString outputFileName = localCacheFilePath(unitUrl);
-#endif
-
-#if QT_CONFIG(temporaryfile)
- // Foo.qml -> Foo.qmlc
- QSaveFile cacheFile(outputFileName);
- if (!cacheFile.open(QIODevice::WriteOnly | QIODevice::Truncate)) {
- *errorString = cacheFile.errorString();
- return false;
- }
-
- QByteArray modifiedUnit;
- modifiedUnit.resize(data->unitSize);
- memcpy(modifiedUnit.data(), data, data->unitSize);
- const char *dataPtr = modifiedUnit.data();
- Unit *unitPtr;
- memcpy(&unitPtr, &dataPtr, sizeof(unitPtr));
- unitPtr->flags |= Unit::StaticData;
-
- qint64 headerWritten = cacheFile.write(modifiedUnit);
- if (headerWritten != modifiedUnit.size()) {
- *errorString = cacheFile.errorString();
- return false;
- }
-
- if (!cacheFile.commit()) {
- *errorString = cacheFile.errorString();
- return false;
- }
-
- return true;
-#else
- Q_UNUSED(outputFileName)
- *errorString = QStringLiteral("features.temporaryfile is disabled.");
- return false;
-#endif // QT_CONFIG(temporaryfile)
-}
-
-void CompilationUnit::setUnitData(const Unit *unitData, const QmlUnit *qmlUnit,
- const QString &fileName, const QString &finalUrlString)
-{
- data = unitData;
- qmlData = nullptr;
-#if Q_BYTE_ORDER == Q_BIG_ENDIAN
- delete [] constants;
-#endif
- constants = nullptr;
- m_fileName.clear();
- m_finalUrlString.clear();
- if (!data)
- return;
-
- qmlData = qmlUnit ? qmlUnit : data->qmlUnit();
-
-#if Q_BYTE_ORDER == Q_BIG_ENDIAN
- Value *bigEndianConstants = new Value[data->constantTableSize];
- const quint64_le *littleEndianConstants = data->constants();
- for (uint i = 0; i < data->constantTableSize; ++i)
- bigEndianConstants[i] = Value::fromReturnedValue(littleEndianConstants[i]);
- constants = bigEndianConstants;
-#else
- constants = reinterpret_cast<const Value*>(data->constants());
-#endif
-
- m_fileName = !fileName.isEmpty() ? fileName : stringAt(data->sourceFileIndex);
- m_finalUrlString = !finalUrlString.isEmpty() ? finalUrlString : stringAt(data->finalUrlIndex);
-}
-
-#ifndef V4_BOOTSTRAP
-QString Binding::valueAsString(const CompilationUnit *unit) const
-{
- switch (type) {
- case Type_Script:
- case Type_String:
- return unit->stringAt(stringIndex);
- case Type_Null:
- return QStringLiteral("null");
- case Type_Boolean:
- return value.b ? QStringLiteral("true") : QStringLiteral("false");
- case Type_Number:
- return QString::number(valueAsNumber(unit->constants));
- case Type_Invalid:
- return QString();
-#if !QT_CONFIG(translation)
- case Type_TranslationById:
- case Type_Translation:
- return unit->stringAt(unit->unitData()->translations()[value.translationDataIndex].stringIndex);
-#else
- case Type_TranslationById: {
- const TranslationData &translation = unit->unitData()->translations()[value.translationDataIndex];
- QByteArray id = unit->stringAt(translation.stringIndex).toUtf8();
- return qtTrId(id.constData(), translation.number);
- }
- case Type_Translation: {
- const TranslationData &translation = unit->unitData()->translations()[value.translationDataIndex];
- // This code must match that in the qsTr() implementation
- const QString &path = unit->fileName();
- int lastSlash = path.lastIndexOf(QLatin1Char('/'));
- QStringRef context = (lastSlash > -1) ? path.midRef(lastSlash + 1, path.length() - lastSlash - 5)
- : QStringRef();
- QByteArray contextUtf8 = context.toUtf8();
- QByteArray comment = unit->stringAt(translation.commentIndex).toUtf8();
- QByteArray text = unit->stringAt(translation.stringIndex).toUtf8();
- return QCoreApplication::translate(contextUtf8.constData(), text.constData(),
- comment.constData(), translation.number);
- }
-#endif
- default:
- break;
- }
- return QString();
-}
-
-//reverse of Lexer::singleEscape()
-QString Binding::escapedString(const QString &string)
-{
- QString tmp = QLatin1String("\"");
- for (int i = 0; i < string.length(); ++i) {
- const QChar &c = string.at(i);
- switch (c.unicode()) {
- case 0x08:
- tmp += QLatin1String("\\b");
- break;
- case 0x09:
- tmp += QLatin1String("\\t");
- break;
- case 0x0A:
- tmp += QLatin1String("\\n");
- break;
- case 0x0B:
- tmp += QLatin1String("\\v");
- break;
- case 0x0C:
- tmp += QLatin1String("\\f");
- break;
- case 0x0D:
- tmp += QLatin1String("\\r");
- break;
- case 0x22:
- tmp += QLatin1String("\\\"");
- break;
- case 0x27:
- tmp += QLatin1String("\\\'");
- break;
- case 0x5C:
- tmp += QLatin1String("\\\\");
- break;
- default:
- tmp += c;
- break;
- }
- }
- tmp += QLatin1Char('\"');
- return tmp;
-}
-
-QString Binding::valueAsScriptString(const CompilationUnit *unit) const
-{
- if (type == Type_String)
- return escapedString(unit->stringAt(stringIndex));
- else
- return valueAsString(unit);
-}
-
-/*!
-Returns the property cache, if one alread exists. The cache is not referenced.
-*/
-QQmlRefPointer<QQmlPropertyCache> ResolvedTypeReference::propertyCache() const
-{
- if (type.isValid())
- return typePropertyCache;
- else
- return compilationUnit->rootPropertyCache();
-}
-
-/*!
-Returns the property cache, creating one if it doesn't already exist. The cache is not referenced.
-*/
-QQmlRefPointer<QQmlPropertyCache> ResolvedTypeReference::createPropertyCache(QQmlEngine *engine)
-{
- if (typePropertyCache) {
- return typePropertyCache;
- } else if (type.isValid()) {
- typePropertyCache = QQmlEnginePrivate::get(engine)->cache(type.metaObject(), minorVersion);
- return typePropertyCache;
- } else {
- return compilationUnit->rootPropertyCache();
- }
-}
-
-bool ResolvedTypeReference::addToHash(QCryptographicHash *hash, QQmlEngine *engine)
-{
- if (type.isValid()) {
- bool ok = false;
- hash->addData(createPropertyCache(engine)->checksum(&ok));
- return ok;
- }
- if (!compilationUnit)
- return false;
- hash->addData(compilationUnit->unitData()->md5Checksum, sizeof(compilationUnit->unitData()->md5Checksum));
- return true;
-}
-
-template <typename T>
-bool qtTypeInherits(const QMetaObject *mo) {
- while (mo) {
- if (mo == &T::staticMetaObject)
- return true;
- mo = mo->superClass();
- }
- return false;
-}
-
-void ResolvedTypeReference::doDynamicTypeCheck()
-{
- const QMetaObject *mo = nullptr;
- if (typePropertyCache)
- mo = typePropertyCache->firstCppMetaObject();
- else if (type.isValid())
- mo = type.metaObject();
- else if (compilationUnit)
- mo = compilationUnit->rootPropertyCache()->firstCppMetaObject();
- isFullyDynamicType = qtTypeInherits<QQmlPropertyMap>(mo);
-}
-
-bool ResolvedTypeReferenceMap::addToHash(QCryptographicHash *hash, QQmlEngine *engine) const
-{
- for (auto it = constBegin(), end = constEnd(); it != end; ++it) {
- if (!it.value()->addToHash(hash, engine))
- return false;
- }
-
- return true;
-}
-
-#endif
-
-void CompilationUnit::destroy()
-{
-#if !defined(V4_BOOTSTRAP)
- if (qmlEngine)
- QQmlEnginePrivate::deleteInEngineThread(qmlEngine, this);
- else
-#endif
- delete this;
-}
-
-
-void Unit::generateChecksum()
-{
-#ifndef V4_BOOTSTRAP
- QCryptographicHash hash(QCryptographicHash::Md5);
-
- const int checksummableDataOffset = offsetof(QV4::CompiledData::Unit, md5Checksum) + sizeof(md5Checksum);
-
- const char *dataPtr = reinterpret_cast<const char *>(this) + checksummableDataOffset;
- hash.addData(dataPtr, unitSize - checksummableDataOffset);
-
- QByteArray checksum = hash.result();
- Q_ASSERT(checksum.size() == sizeof(md5Checksum));
- memcpy(md5Checksum, checksum.constData(), sizeof(md5Checksum));
-#else
- memset(md5Checksum, 0, sizeof(md5Checksum));
-#endif
-}
-
-bool Unit::verifyHeader(QDateTime expectedSourceTimeStamp, QString *errorString) const
-{
-#ifndef V4_BOOTSTRAP
- if (strncmp(magic, CompiledData::magic_str, sizeof(magic))) {
- *errorString = QStringLiteral("Magic bytes in the header do not match");
- return false;
- }
-
- if (version != quint32(QV4_DATA_STRUCTURE_VERSION)) {
- *errorString = QString::fromUtf8("V4 data structure version mismatch. Found %1 expected %2").arg(version, 0, 16).arg(QV4_DATA_STRUCTURE_VERSION, 0, 16);
- return false;
- }
-
- if (qtVersion != quint32(QT_VERSION)) {
- *errorString = QString::fromUtf8("Qt version mismatch. Found %1 expected %2").arg(qtVersion, 0, 16).arg(QT_VERSION, 0, 16);
- return false;
- }
-
- if (sourceTimeStamp) {
- // Files from the resource system do not have any time stamps, so fall back to the application
- // executable.
- if (!expectedSourceTimeStamp.isValid())
- expectedSourceTimeStamp = QFileInfo(QCoreApplication::applicationFilePath()).lastModified();
-
- if (expectedSourceTimeStamp.isValid() && expectedSourceTimeStamp.toMSecsSinceEpoch() != sourceTimeStamp) {
- *errorString = QStringLiteral("QML source file has a different time stamp than cached file.");
- return false;
- }
- }
-
-#if defined(QML_COMPILE_HASH)
- if (qstrcmp(CompiledData::qml_compile_hash, libraryVersionHash) != 0) {
- *errorString = QStringLiteral("QML library version mismatch. Expected compile hash does not match");
- return false;
- }
-#else
-#error "QML_COMPILE_HASH must be defined for the build of QtDeclarative to ensure version checking for cache files"
-#endif
-
- return true;
-#else
- Q_UNUSED(expectedSourceTimeStamp)
- Q_UNUSED(errorString)
- return false;
-#endif
-}
-
-Location &Location::operator=(const QQmlJS::AST::SourceLocation &astLocation)
-{
- line = astLocation.startLine;
- column = astLocation.startColumn;
- return *this;
-}
-
-}
-
-}
-
-QT_END_NAMESPACE
diff --git a/src/qml/compiler/qv4compileddata_p.h b/src/qml/compiler/qv4compileddata_p.h
deleted file mode 100644
index 7b26939da0..0000000000
--- a/src/qml/compiler/qv4compileddata_p.h
+++ /dev/null
@@ -1,1316 +0,0 @@
-/****************************************************************************
-**
-** 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/qendian_p.h>
-#include <private/qqmljsastfwd_p.h>
-#ifndef V4_BOOTSTRAP
-#include <private/qqmltypenamecache_p.h>
-#include <private/qqmlpropertycache_p.h>
-#include "private/qintrusivelist_p.h"
-#endif
-
-QT_BEGIN_NAMESPACE
-
-// Bump this whenever the compiler data structures change in an incompatible way.
-#define QV4_DATA_STRUCTURE_VERSION 0x21
-
-class QIODevice;
-class QQmlPropertyCache;
-class QQmlPropertyData;
-class QQmlTypeNameCache;
-class QQmlScriptData;
-class QQmlType;
-class QQmlEngine;
-
-namespace QmlIR {
-struct Document;
-}
-
-namespace QV4 {
-
-namespace Heap {
-struct Module;
-};
-
-struct Function;
-class EvalISelFactory;
-class CompilationUnitMapper;
-
-namespace CompiledData {
-
-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; }
-};
-
-struct Location
-{
- union {
- quint32 _dummy;
- quint32_le_bitfield<0, 20> line;
- quint32_le_bitfield<20, 12> column;
- };
-
- Location() : _dummy(0) { }
-
- Location &operator=(const QQmlJS::AST::SourceLocation &astLocation);
-
- inline bool operator<(const Location &other) const {
- return line < other.line ||
- (line == other.line && column < other.column);
- }
-};
-static_assert(sizeof(Location) == 4, "Location structure needs to have the expected size to be binary compatible on disk when generated by host compiler and loaded by target");
-
-struct RegExp
-{
- enum Flags : unsigned int {
- RegExp_NoFlags = 0x0,
- RegExp_Global = 0x01,
- RegExp_IgnoreCase = 0x02,
- RegExp_Multiline = 0x04,
- RegExp_Unicode = 0x08,
- RegExp_Sticky = 0x10
- };
- union {
- quint32 _dummy;
- quint32_le_bitfield<0, 5> flags;
- quint32_le_bitfield<5, 27> stringIndex;
- };
-
- RegExp() : _dummy(0) { }
-};
-static_assert(sizeof(RegExp) == 4, "RegExp structure needs to have the expected size to be binary compatible on disk when generated by host compiler and loaded by target");
-
-struct Lookup
-{
- enum Type : unsigned int {
- Type_Getter = 0,
- Type_Setter = 1,
- Type_GlobalGetter = 2,
- Type_QmlContextPropertyGetter = 3
- };
-
- union {
- quint32 _dummy;
- quint32_le_bitfield<0, 4> type_and_flags;
- quint32_le_bitfield<4, 28> nameIndex;
- };
-
- Lookup() : _dummy(0) { }
-};
-static_assert(sizeof(Lookup) == 4, "Lookup structure needs to have the expected size to be binary compatible on disk when generated by host compiler and loaded by target");
-
-struct JSClassMember
-{
- union {
- quint32 _dummy;
- quint32_le_bitfield<0, 31> nameOffset;
- quint32_le_bitfield<31, 1> isAccessor;
- };
-
- JSClassMember() : _dummy(0) { }
-};
-static_assert(sizeof(JSClassMember) == 4, "JSClassMember structure needs to have the expected size to be binary compatible on disk when generated by host compiler and loaded by target");
-
-struct JSClass
-{
- quint32_le nMembers;
- // JSClassMember[nMembers]
-
- static int calculateSize(int nMembers) { return (sizeof(JSClass) + nMembers * sizeof(JSClassMember) + 7) & ~7; }
-};
-static_assert(sizeof(JSClass) == 4, "JSClass structure needs to have the expected size to be binary compatible on disk when generated by host compiler and loaded by target");
-
-// This data structure is intended to be binary compatible with QStringData/QStaticStringData on
-// 64-bit and 32-bit little-endian architectures, in all directions. So the same structure mapped
-// from a file must be castable to a QStringData regardless of the pointer size. With the first
-// few fields that's easy, they're always 32-bit. However the offset field of QArrayData is a
-// ptrdiff_t and thus variable in size.
-// On 64-bit systems compilers enforce an 8-byte alignment and thus place it at offset 16, while
-// on 32-bit systems offset 12 is sufficient. Therefore the two values don't overlap and contain
-// the same value.
-struct String
-{
- qint32_le refcount; // -1
- qint32_le size;
- quint32_le allocAndCapacityReservedFlag; // 0
- quint32_le offsetOn32Bit;
- quint64_le offsetOn64Bit;
- // uint16 strdata[]
-
- static int calculateSize(const QString &str) {
- return (sizeof(String) + (str.length() + 1) * sizeof(quint16) + 7) & ~0x7;
- }
-};
-static_assert(sizeof(String) == 24, "String structure needs to have the expected size to be binary compatible on disk when generated by host compiler and loaded by target");
-
-// Ensure compatibility with QString
-static_assert(offsetof(QArrayData, ref) == offsetof(String, refcount), "refcount must be at the same location");
-static_assert(offsetof(QArrayData, size) == offsetof(String, size), "size must be at the same location");
-static_assert(offsetof(String, offsetOn64Bit) == 16, "offset must be at 8-byte aligned location");
-static_assert(offsetof(String, offsetOn32Bit) == 12, "offset must be at 4-byte aligned location");
-#if QT_POINTER_SIZE == 8
-static_assert(offsetof(QArrayData, offset) == offsetof(String, offsetOn64Bit), "offset must be at the same location");
-#else
-static_assert(offsetof(QArrayData, offset) == offsetof(String, offsetOn32Bit), "offset must be at the same location");
-#endif
-
-struct CodeOffsetToLine {
- quint32_le codeOffset;
- quint32_le line;
-};
-static_assert(sizeof(CodeOffsetToLine) == 8, "CodeOffsetToLine structure needs to have the expected size to be binary compatible on disk when generated by host compiler and loaded by target");
-
-struct Block
-{
- quint32_le nLocals;
- quint32_le localsOffset;
- quint16_le sizeOfLocalTemporalDeadZone;
- quint16_le padding;
-
- const quint32_le *localsTable() const { return reinterpret_cast<const quint32_le *>(reinterpret_cast<const char *>(this) + localsOffset); }
-
- static int calculateSize(int nLocals) {
- int trailingData = nLocals*sizeof (quint32);
- size_t size = align(align(sizeof(Block)) + size_t(trailingData));
- Q_ASSERT(size < INT_MAX);
- return int(size);
- }
-
- static size_t align(size_t a) {
- return (a + 7) & ~size_t(7);
- }
-};
-static_assert(sizeof(Block) == 12, "Block structure needs to have the expected size to be binary compatible on disk when generated by host compiler and loaded by target");
-
-// 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 : unsigned int {
- IsStrict = 0x1,
- IsArrowFunction = 0x2,
- IsGenerator = 0x4
- };
-
- // Absolute offset into file where the code for this function is located.
- quint32_le codeOffset;
- quint32_le codeSize;
-
- quint32_le nameIndex;
- quint16_le length;
- quint16_le nFormals;
- quint32_le formalsOffset; // Can't turn this into a calculated offset because of the mutation in CompilationUnit::createUnitData.
- quint32_le localsOffset;
- quint16_le nLocals;
- quint16_le nLineNumbers;
- size_t lineNumberOffset() const { return localsOffset + nLocals * sizeof(quint32); }
- quint32_le nestedFunctionIndex; // for functions that only return a single closure, used in signal handlers
- quint16_le sizeOfLocalTemporalDeadZone;
- quint16_le firstTemporalDeadZoneRegister;
- quint16_le sizeOfRegisterTemporalDeadZone;
- quint16_le nRegisters;
- Location location;
-
- quint32_le nLabelInfos;
- size_t labelInfosOffset() const { return lineNumberOffset() + nLineNumbers * sizeof(CodeOffsetToLine); }
-
- typedef quint16_le TraceInfoCount;
- TraceInfoCount nTraceInfos;
- static Q_DECL_CONSTEXPR TraceInfoCount NoTracing() { return TraceInfoCount::max(); }
-
- // Keep all unaligned data at the end
- quint8 flags;
- quint8 padding1;
-
- // quint32 formalsIndex[nFormals]
- // quint32 localsIndex[nLocals]
-
- const quint32_le *formalsTable() const { return reinterpret_cast<const quint32_le *>(reinterpret_cast<const char *>(this) + formalsOffset); }
- const quint32_le *localsTable() const { return reinterpret_cast<const quint32_le *>(reinterpret_cast<const char *>(this) + localsOffset); }
- const CodeOffsetToLine *lineNumberTable() const { return reinterpret_cast<const CodeOffsetToLine *>(reinterpret_cast<const char *>(this) + lineNumberOffset()); }
-
- // --- QQmlPropertyCacheCreator interface
- const quint32_le *formalsBegin() const { return formalsTable(); }
- const quint32_le *formalsEnd() const { return formalsTable() + nFormals; }
- // ---
-
- const quint32_le *labelInfoTable() const { return reinterpret_cast<const quint32_le *>(reinterpret_cast<const char *>(this) + labelInfosOffset()); }
-
- const char *code() const { return reinterpret_cast<const char *>(this) + codeOffset; }
-
- static int calculateSize(int nFormals, int nLocals, int nLines, int nInnerfunctions, int labelInfoSize, int codeSize) {
- int trailingData = (nFormals + nLocals + nInnerfunctions + labelInfoSize)*sizeof (quint32)
- + nLines*sizeof(CodeOffsetToLine);
- size_t size = align(align(sizeof(Function)) + size_t(trailingData)) + align(codeSize);
- Q_ASSERT(size < INT_MAX);
- return int(size);
- }
-
- static size_t align(size_t a) {
- return (a + 7) & ~size_t(7);
- }
-};
-static_assert(sizeof(Function) == 52, "Function structure needs to have the expected size to be binary compatible on disk when generated by host compiler and loaded by target");
-
-struct Method {
- enum Type {
- Regular,
- Getter,
- Setter
- };
-
- quint32_le name;
- quint32_le type;
- quint32_le function;
-};
-static_assert(sizeof(Method) == 12, "Method structure needs to have the expected size to be binary compatible on disk when generated by host compiler and loaded by target");
-
-struct Class
-{
- quint32_le nameIndex;
- quint32_le scopeIndex;
- quint32_le constructorFunction;
- quint32_le nStaticMethods;
- quint32_le nMethods;
- quint32_le methodTableOffset;
-
- const Method *methodTable() const { return reinterpret_cast<const Method *>(reinterpret_cast<const char *>(this) + methodTableOffset); }
-
- static int calculateSize(int nStaticMethods, int nMethods) {
- int trailingData = (nStaticMethods + nMethods) * sizeof(Method);
- size_t size = align(sizeof(Class) + trailingData);
- Q_ASSERT(size < INT_MAX);
- return int(size);
- }
-
- static size_t align(size_t a) {
- return (a + 7) & ~size_t(7);
- }
-};
-static_assert(sizeof(Class) == 24, "Class structure needs to have the expected size to be binary compatible on disk when generated by host compiler and loaded by target");
-
-struct TemplateObject
-{
- quint32_le size;
-
- static int calculateSize(int size) {
- int trailingData = 2 * size * sizeof(quint32_le);
- size_t s = align(sizeof(TemplateObject) + trailingData);
- Q_ASSERT(s < INT_MAX);
- return int(s);
- }
-
- static size_t align(size_t a) {
- return (a + 7) & ~size_t(7);
- }
-
- const quint32_le *stringTable() const {
- return reinterpret_cast<const quint32_le *>(reinterpret_cast<const char *>(this + 1));
- }
-
- uint stringIndexAt(uint i) const {
- return stringTable()[i];
- }
- uint rawStringIndexAt(uint i) const {
- return stringTable()[size + i];
- }
-};
-static_assert(sizeof(TemplateObject) == 4, "Template object structure needs to have the expected size to be binary compatible on disk when generated by host compiler and loaded by target");
-
-struct ExportEntry
-{
- quint32_le exportName;
- quint32_le moduleRequest;
- quint32_le importName;
- quint32_le localName;
- Location location;
-};
-static_assert(sizeof(ExportEntry) == 20, "ExportEntry structure needs to have the expected size to be binary compatible on disk when generated by host compiler and loaded by target");
-
-struct ImportEntry
-{
- quint32_le moduleRequest;
- quint32_le importName;
- quint32_le localName;
- Location location;
-};
-static_assert(sizeof(ImportEntry) == 16, "ImportEntry structure needs to have the expected size to be binary compatible on disk when generated by host compiler and loaded by target");
-
-// Qml data structures
-
-struct Q_QML_EXPORT TranslationData
-{
- quint32_le stringIndex;
- quint32_le commentIndex;
- qint32_le number;
- quint32_le padding;
-};
-static_assert(sizeof(TranslationData) == 16, "TranslationData structure needs to have the expected size to be binary compatible on disk when generated by host compiler and loaded by target");
-
-struct Q_QML_PRIVATE_EXPORT Binding
-{
- quint32_le propertyNameIndex;
-
- enum ValueType : unsigned int {
- Type_Invalid,
- Type_Boolean,
- Type_Number,
- Type_String,
- Type_Null,
- 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,
- IsFunctionExpression = 0x200
- };
-
- union {
- quint32_le_bitfield<0, 16> flags;
- quint32_le_bitfield<16, 16> type;
- };
- union {
- bool b;
- quint32_le constantValueIndex;
- quint32_le compiledScriptIndex; // used when Type_Script
- quint32_le objectIndex;
- quint32_le translationDataIndex; // used when Type_Translation
- quint32 nullMarker;
- } value;
- quint32_le stringIndex; // Set for Type_String 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;
- }
-
- bool isFunctionExpression() const { return (flags & IsFunctionExpression); }
-
- static QString escapedString(const QString &string);
-
- bool isTranslationBinding() const { return type == Type_Translation || type == Type_TranslationById; }
- bool evaluatesToString() const { return type == Type_String || isTranslationBinding(); }
-
-#ifndef V4_BOOTSTRAP
- QString valueAsString(const CompilationUnit *unit) const;
- QString valueAsScriptString(const CompilationUnit *unit) const;
-#endif
- double valueAsNumber(const Value *constantTable) const
- {
- if (type != Type_Number)
- return 0.0;
- return constantTable[value.constantValueIndex].doubleValue();
- }
-
- bool valueAsBoolean() const
- {
- if (type == Type_Boolean)
- return value.b;
- return false;
- }
-
-};
-
-static_assert(sizeof(Binding) == 24, "Binding structure needs to have the expected size to be binary compatible on disk when generated by host compiler and loaded by target");
-
-struct EnumValue
-{
- quint32_le nameIndex;
- qint32_le value;
- Location location;
-};
-static_assert(sizeof(EnumValue) == 12, "EnumValue structure needs to have the expected size to be binary compatible on disk when generated by host compiler and loaded by target");
-
-struct Enum
-{
- quint32_le nameIndex;
- quint32_le nEnumValues;
- Location location;
-
- const EnumValue *enumValueAt(int idx) const {
- return reinterpret_cast<const EnumValue*>(this + 1) + idx;
- }
-
- static int calculateSize(int nEnumValues) {
- return (sizeof(Enum)
- + nEnumValues * sizeof(EnumValue)
- + 7) & ~0x7;
- }
-
- // --- QQmlPropertyCacheCreatorInterface
- const EnumValue *enumValuesBegin() const { return enumValueAt(0); }
- const EnumValue *enumValuesEnd() const { return enumValueAt(nEnumValues); }
- int enumValueCount() const { return nEnumValues; }
- // ---
-};
-static_assert(sizeof(Enum) == 12, "Enum structure needs to have the expected size to be binary compatible on disk when generated by host compiler and loaded by target");
-
-struct Parameter
-{
- quint32_le nameIndex;
- quint32_le type;
- quint32_le customTypeNameIndex;
- Location location;
-};
-static_assert(sizeof(Parameter) == 16, "Parameter structure needs to have the expected size to be binary compatible on disk when generated by host compiler and loaded by target");
-
-struct Signal
-{
- quint32_le nameIndex;
- quint32_le 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; }
- // ---
-};
-static_assert(sizeof(Signal) == 12, "Signal structure needs to have the expected size to be binary compatible on disk when generated by host compiler and loaded by target");
-
-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
- };
-
- quint32_le nameIndex;
- union {
- quint32_le_bitfield<0, 31> type;
- quint32_le_bitfield<31, 1> flags; // readonly
- };
- quint32_le customTypeNameIndex; // If type >= Custom
- Location location;
-};
-static_assert(sizeof(Property) == 16, "Property structure needs to have the expected size to be binary compatible on disk when generated by host compiler and loaded by target");
-
-struct Alias {
- enum Flags : unsigned int {
- IsReadOnly = 0x1,
- Resolved = 0x2,
- AliasPointsToPointerObject = 0x4
- };
- union {
- quint32_le_bitfield<0, 29> nameIndex;
- quint32_le_bitfield<29, 3> flags;
- };
- union {
- quint32_le idIndex; // string index
- quint32_le_bitfield<0, 31> targetObjectId; // object id index (in QQmlContextData::idValues)
- quint32_le_bitfield<31, 1> aliasToLocalAlias;
- };
- union {
- quint32_le propertyNameIndex; // string index
- qint32_le encodedMetaPropertyIndex;
- quint32_le 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;
- }
-};
-static_assert(sizeof(Alias) == 20, "Alias structure needs to have the expected size to be binary compatible on disk when generated by host compiler and loaded by target");
-
-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_le inheritedTypeNameIndex;
- quint32_le idNameIndex;
- union {
- quint32_le_bitfield<0, 15> flags;
- quint32_le_bitfield<15, 1> defaultPropertyIsAlias;
- qint32_le_bitfield<16, 16> id;
- };
- qint32_le indexOfDefaultPropertyOrAlias; // -1 means no default property declared in this object
- quint16_le nFunctions;
- quint16_le nProperties;
- quint32_le offsetToFunctions;
- quint32_le offsetToProperties;
- quint32_le offsetToAliases;
- quint16_le nAliases;
- quint16_le nEnums;
- quint32_le offsetToEnums; // which in turn will be a table with offsets to variable-sized Enum objects
- quint32_le offsetToSignals; // which in turn will be a table with offsets to variable-sized Signal objects
- quint16_le nSignals;
- quint16_le nBindings;
- quint32_le offsetToBindings;
- quint32_le nNamedObjectsInComponent;
- quint32_le offsetToNamedObjectsInComponent;
- Location location;
- Location locationOfIdProperty;
-// Function[]
-// Property[]
-// Signal[]
-// Binding[]
-
- static int calculateSizeExcludingSignalsAndEnums(int nFunctions, int nProperties, int nAliases, int nEnums, int nSignals, int nBindings, int nNamedObjectsInComponent)
- {
- return ( sizeof(Object)
- + nFunctions * sizeof(quint32)
- + nProperties * sizeof(Property)
- + nAliases * sizeof(Alias)
- + nEnums * sizeof(quint32)
- + nSignals * sizeof(quint32)
- + nBindings * sizeof(Binding)
- + nNamedObjectsInComponent * sizeof(int)
- + 0x7
- ) & ~0x7;
- }
-
- const quint32_le *functionOffsetTable() const
- {
- return reinterpret_cast<const quint32_le*>(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 Enum *enumAt(int idx) const
- {
- const quint32_le *offsetTable = reinterpret_cast<const quint32_le*>((reinterpret_cast<const char *>(this)) + offsetToEnums);
- const quint32_le offset = offsetTable[idx];
- return reinterpret_cast<const Enum*>(reinterpret_cast<const char*>(this) + offset);
- }
-
- const Signal *signalAt(int idx) const
- {
- const quint32_le *offsetTable = reinterpret_cast<const quint32_le*>((reinterpret_cast<const char *>(this)) + offsetToSignals);
- const quint32_le offset = offsetTable[idx];
- return reinterpret_cast<const Signal*>(reinterpret_cast<const char*>(this) + offset);
- }
-
- const quint32_le *namedObjectsInComponentTable() const
- {
- return reinterpret_cast<const quint32_le*>(reinterpret_cast<const char *>(this) + offsetToNamedObjectsInComponent);
- }
-
- // --- QQmlPropertyCacheCreator interface
- int propertyCount() const { return nProperties; }
- int aliasCount() const { return nAliases; }
- int enumCount() const { return nEnums; }
- 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<Enum, Object, &Object::enumAt> EnumIterator;
- EnumIterator enumsBegin() const { return EnumIterator(this, 0); }
- EnumIterator enumsEnd() const { return EnumIterator(this, nEnums); }
-
- 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; }
- // ---
-};
-static_assert(sizeof(Object) == 68, "Object structure needs to have the expected size to be binary compatible on disk when generated by host compiler and loaded by target");
-
-struct Import
-{
- enum ImportType : unsigned int {
- ImportLibrary = 0x1,
- ImportFile = 0x2,
- ImportScript = 0x3
- };
- quint32_le type;
-
- quint32_le uriIndex;
- quint32_le qualifierIndex;
-
- qint32_le majorVersion;
- qint32_le minorVersion;
-
- Location location;
-
- Import() { type = 0; uriIndex = 0; qualifierIndex = 0; majorVersion = 0; minorVersion = 0; }
-};
-static_assert(sizeof(Import) == 24, "Import structure needs to have the expected size to be binary compatible on disk when generated by host compiler and loaded by target");
-
-struct QmlUnit
-{
- quint32_le nImports;
- quint32_le offsetToImports;
- quint32_le nObjects;
- quint32_le offsetToObjects;
-
- 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 quint32_le *offsetTable = reinterpret_cast<const quint32_le*>((reinterpret_cast<const char *>(this)) + offsetToObjects);
- const quint32_le offset = offsetTable[idx];
- return reinterpret_cast<const Object*>(reinterpret_cast<const char*>(this) + offset);
- }
-};
-static_assert(sizeof(QmlUnit) == 16, "QmlUnit structure needs to have the expected size to be binary compatible on disk when generated by host compiler and loaded by target");
-
-enum { QmlCompileHashSpace = 48 };
-static const char magic_str[] = "qv4cdata";
-extern const char qml_compile_hash[QmlCompileHashSpace + 1];
-
-struct Unit
-{
- // DO NOT CHANGE THESE FIELDS EVER
- char magic[8];
- quint32_le version;
- quint32_le qtVersion;
- qint64_le sourceTimeStamp;
- quint32_le unitSize; // Size of the Unit and any depending data.
- // END DO NOT CHANGE THESE FIELDS EVER
-
- char libraryVersionHash[QmlCompileHashSpace];
-
- char md5Checksum[16]; // checksum of all bytes following this field.
- void generateChecksum();
-
- char dependencyMD5Checksum[16];
-
- enum : unsigned int {
- IsJavascript = 0x1,
- StaticData = 0x2, // Unit data persistent in memory?
- IsSingleton = 0x4,
- IsSharedLibrary = 0x8, // .pragma shared?
- IsESModule = 0x10,
- PendingTypeCompilation = 0x20 // the QML data structures present are incomplete and require type compilation
- };
- quint32_le flags;
- quint32_le stringTableSize;
- quint32_le offsetToStringTable;
- quint32_le functionTableSize;
- quint32_le offsetToFunctionTable;
- quint32_le classTableSize;
- quint32_le offsetToClassTable;
- quint32_le templateObjectTableSize;
- quint32_le offsetToTemplateObjectTable;
- quint32_le blockTableSize;
- quint32_le offsetToBlockTable;
- quint32_le lookupTableSize;
- quint32_le offsetToLookupTable;
- quint32_le regexpTableSize;
- quint32_le offsetToRegexpTable;
- quint32_le constantTableSize;
- quint32_le offsetToConstantTable;
- quint32_le jsClassTableSize;
- quint32_le offsetToJSClassTable;
- quint32_le translationTableSize;
- quint32_le offsetToTranslationTable;
- quint32_le localExportEntryTableSize;
- quint32_le offsetToLocalExportEntryTable;
- quint32_le indirectExportEntryTableSize;
- quint32_le offsetToIndirectExportEntryTable;
- quint32_le starExportEntryTableSize;
- quint32_le offsetToStarExportEntryTable;
- quint32_le importEntryTableSize;
- quint32_le offsetToImportEntryTable;
- quint32_le moduleRequestTableSize;
- quint32_le offsetToModuleRequestTable;
- qint32_le indexOfRootFunction;
- quint32_le sourceFileIndex;
- quint32_le finalUrlIndex;
-
- quint32_le offsetToQmlUnit;
-
- bool verifyHeader(QDateTime expectedSourceTimeStamp, QString *errorString) const;
-
- /* QML specific fields */
-
- const QmlUnit *qmlUnit() const {
- return reinterpret_cast<const QmlUnit *>(reinterpret_cast<const char *>(this) + offsetToQmlUnit);
- }
-
- QmlUnit *qmlUnit() {
- return reinterpret_cast<QmlUnit *>(reinterpret_cast<char *>(this) + offsetToQmlUnit);
- }
-
- bool isSingleton() const {
- return flags & Unit::IsSingleton;
- }
- /* end QML specific fields*/
-
- QString stringAtInternal(int idx) const {
- Q_ASSERT(idx < int(stringTableSize));
- const quint32_le *offsetTable = reinterpret_cast<const quint32_le*>((reinterpret_cast<const char *>(this)) + offsetToStringTable);
- const quint32_le 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
- if (flags & StaticData) {
- const QStringDataPtr holder = { const_cast<QStringData *>(reinterpret_cast<const QStringData*>(str)) };
- return QString(holder);
- }
- const QChar *characters = reinterpret_cast<const QChar *>(str + 1);
- return QString(characters, str->size);
-#else
- const quint16_le *characters = reinterpret_cast<const quint16_le *>(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 quint32_le *functionOffsetTable() const { return reinterpret_cast<const quint32_le*>((reinterpret_cast<const char *>(this)) + offsetToFunctionTable); }
- const quint32_le *classOffsetTable() const { return reinterpret_cast<const quint32_le*>((reinterpret_cast<const char *>(this)) + offsetToClassTable); }
- const quint32_le *templateObjectOffsetTable() const { return reinterpret_cast<const quint32_le*>((reinterpret_cast<const char *>(this)) + offsetToTemplateObjectTable); }
- const quint32_le *blockOffsetTable() const { return reinterpret_cast<const quint32_le*>((reinterpret_cast<const char *>(this)) + offsetToBlockTable); }
-
- const Function *functionAt(int idx) const {
- const quint32_le *offsetTable = functionOffsetTable();
- const quint32_le offset = offsetTable[idx];
- return reinterpret_cast<const Function*>(reinterpret_cast<const char *>(this) + offset);
- }
-
- const Class *classAt(int idx) const {
- const quint32_le *offsetTable = classOffsetTable();
- const quint32_le offset = offsetTable[idx];
- return reinterpret_cast<const Class *>(reinterpret_cast<const char *>(this) + offset);
- }
-
- const TemplateObject *templateObjectAt(int idx) const {
- const quint32_le *offsetTable = templateObjectOffsetTable();
- const quint32_le offset = offsetTable[idx];
- return reinterpret_cast<const TemplateObject *>(reinterpret_cast<const char *>(this) + offset);
- }
-
- const Block *blockAt(int idx) const {
- const quint32_le *offsetTable = blockOffsetTable();
- const quint32_le offset = offsetTable[idx];
- return reinterpret_cast<const Block *>(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 quint64_le *constants() const {
- return reinterpret_cast<const quint64_le*>(reinterpret_cast<const char *>(this) + offsetToConstantTable);
- }
-
- const JSClassMember *jsClassAt(int idx, int *nMembers) const {
- const quint32_le *offsetTable = reinterpret_cast<const quint32_le *>(reinterpret_cast<const char *>(this) + offsetToJSClassTable);
- const quint32_le 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));
- }
-
- const TranslationData *translations() const {
- return reinterpret_cast<const TranslationData *>(reinterpret_cast<const char *>(this) + offsetToTranslationTable);
- }
-
- const ImportEntry *importEntryTable() const { return reinterpret_cast<const ImportEntry *>(reinterpret_cast<const char *>(this) + offsetToImportEntryTable); }
- const ExportEntry *localExportEntryTable() const { return reinterpret_cast<const ExportEntry *>(reinterpret_cast<const char *>(this) + offsetToLocalExportEntryTable); }
- const ExportEntry *indirectExportEntryTable() const { return reinterpret_cast<const ExportEntry *>(reinterpret_cast<const char *>(this) + offsetToIndirectExportEntryTable); }
- const ExportEntry *starExportEntryTable() const { return reinterpret_cast<const ExportEntry *>(reinterpret_cast<const char *>(this) + offsetToStarExportEntryTable); }
-
- const quint32_le *moduleRequestTable() const { return reinterpret_cast<const quint32_le*>((reinterpret_cast<const char *>(this)) + offsetToModuleRequestTable); }
-};
-
-static_assert(sizeof(Unit) == 248, "Unit structure needs to have the expected size to be binary compatible on disk when generated by host compiler and loaded by target");
-
-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;
- }
-
- auto prop = obj->propertiesBegin();
- auto propEnd = obj->propertiesEnd();
- for ( ; prop != propEnd; ++prop) {
- if (prop->type >= QV4::CompiledData::Property::Custom) {
- TypeReference &r = this->add(prop->customTypeNameIndex, prop->location);
- r.errorWhenNotFound = true;
- }
- }
-
- auto binding = obj->bindingsBegin();
- auto bindingEnd = obj->bindingsEnd();
- for ( ; 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;
-// 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;
-};
-
-using DependentTypesHasher = std::function<bool(QCryptographicHash *)>;
-#else
-struct DependentTypesHasher {};
-#endif
-
-// index is per-object binding index
-typedef QVector<QQmlPropertyData*> BindingPropertyData;
-
-// This is how this hooks into the existing structures:
-
-struct Q_QML_PRIVATE_EXPORT CompilationUnitBase
-{
- // pointers either to data->constants() or little-endian memory copy.
- QV4::Heap::String **runtimeStrings = nullptr; // Array
- const Value* constants = nullptr;
- QV4::Value *runtimeRegularExpressions = nullptr;
- QV4::Heap::InternalClass **runtimeClasses = nullptr;
- const Value** imports = nullptr;
-};
-
-Q_STATIC_ASSERT(std::is_standard_layout<CompilationUnitBase>::value);
-Q_STATIC_ASSERT(offsetof(CompilationUnitBase, runtimeStrings) == 0);
-Q_STATIC_ASSERT(offsetof(CompilationUnitBase, constants) == sizeof(QV4::Heap::String **));
-Q_STATIC_ASSERT(offsetof(CompilationUnitBase, runtimeRegularExpressions) == offsetof(CompilationUnitBase, constants) + sizeof(const Value *));
-Q_STATIC_ASSERT(offsetof(CompilationUnitBase, runtimeClasses) == offsetof(CompilationUnitBase, runtimeRegularExpressions) + sizeof(const Value *));
-Q_STATIC_ASSERT(offsetof(CompilationUnitBase, imports) == offsetof(CompilationUnitBase, runtimeClasses) + sizeof(const Value *));
-
-struct Q_QML_PRIVATE_EXPORT CompilationUnit final : public CompilationUnitBase
-{
- const Unit *data = nullptr;
- const QmlUnit *qmlData = nullptr;
-public:
- CompilationUnit(const Unit *unitData = nullptr, const QString &fileName = QString(), const QString &finalUrlString = QString());
- ~CompilationUnit();
-
- void addref()
- {
- Q_ASSERT(refCount.load() > 0);
- refCount.ref();
- }
-
- void release()
- {
- Q_ASSERT(refCount.load() > 0);
- if (!refCount.deref())
- destroy();
- }
- int count() const
- {
- return refCount.load();
- }
-
- const Unit *unitData() const { return data; }
- void setUnitData(const Unit *unitData, const QmlUnit *qmlUnit = nullptr,
- const QString &fileName = QString(), const QString &finalUrlString = QString());
-
-#ifndef V4_BOOTSTRAP
- QIntrusiveListNode nextCompilationUnit;
- ExecutionEngine *engine = nullptr;
- QQmlEnginePrivate *qmlEngine = nullptr; // only used in QML environment for composite types, not in plain QJSEngine case.
-
- // url() and fileName() shall be used to load the actual QML/JS code or to show errors or
- // warnings about that code. They include any potential URL interceptions and thus represent the
- // "physical" location of the code.
- //
- // finalUrl() and finalUrlString() shall be used to resolve further URLs referred to in the code
- // They are _not_ intercepted and thus represent the "logical" name for the code.
-
- QString fileName() const { return m_fileName; }
- QString finalUrlString() const { return m_finalUrlString; }
- QUrl url() const { if (m_url.isNull) m_url = QUrl(fileName()); return m_url; }
- QUrl finalUrl() const
- {
- if (m_finalUrl.isNull)
- m_finalUrl = QUrl(finalUrlString());
- return m_finalUrl;
- }
-
- QV4::Lookup *runtimeLookups = nullptr;
- QVector<QV4::Function *> runtimeFunctions;
- QVector<QV4::Heap::InternalClass *> runtimeBlocks;
- mutable QVector<QV4::Heap::Object *> templateObjects;
- mutable QQmlNullableValue<QUrl> m_url;
- mutable QQmlNullableValue<QUrl> m_finalUrl;
-
- // QML specific fields
- QQmlPropertyCacheVector propertyCaches;
- QQmlRefPointer<QQmlPropertyCache> rootPropertyCache() const { return propertyCaches.at(/*root object*/0); }
-
- QQmlRefPointer<QQmlTypeNameCache> typeNameCache;
-
- // 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> namedObjectsPerComponentCache;
- inline IdentifierHash namedObjectsPerComponent(int componentObjectIndex);
-
- void finalizeCompositeType(QQmlEnginePrivate *qmlEngine);
-
- int totalBindingsCount = 0; // Number of bindings used in this type
- int totalParserStatusCount = 0; // Number of instantiated types that are QQmlParserStatus subclasses
- int totalObjectCount = 0; // Number of objects explicitly instantiated
-
- QVector<QQmlRefPointer<QQmlScriptData>> dependentScripts;
- ResolvedTypeReferenceMap resolvedTypes;
- ResolvedTypeReference *resolvedType(int id) const { return resolvedTypes.value(id); }
-
- bool verifyChecksum(const DependentTypesHasher &dependencyHasher) const;
-
- int metaTypeId = -1;
- int listMetaTypeId = -1;
- bool isRegisteredWithEngine = false;
-
- QScopedPointer<CompilationUnitMapper> backingFile;
- QStringList dynamicStrings;
-
- // --- interface for QQmlPropertyCacheCreator
- typedef Object CompiledObject;
- int objectCount() const { return qmlData->nObjects; }
- const Object *objectAt(int index) const { return qmlData->objectAt(index); }
- int importCount() const { return qmlData->nImports; }
- const Import *importAt(int index) const { return qmlData->importAt(index); }
- QString stringAt(int index) const
- {
- if (uint(index) >= data->stringTableSize)
- return dynamicStrings.at(index - data->stringTableSize);
- return data->stringAtInternal(index);
- }
-
- Heap::Object *templateObjectAt(int index) const;
-
- 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); }
- // ---
-
- bool isESModule() const { return data->flags & Unit::IsESModule; }
- bool isSharedLibrary() const { return data->flags & Unit::IsSharedLibrary; }
- QStringList moduleRequests() const;
- Heap::Module *instantiate(ExecutionEngine *engine);
- const Value *resolveExport(QV4::String *exportName);
- QStringList exportedNames() const;
- void evaluate();
- void evaluateModuleRequests();
-
- QV4::Function *linkToEngine(QV4::ExecutionEngine *engine);
- void unlink();
-
- void markObjects(MarkStack *markStack);
-
- bool loadFromDisk(const QUrl &url, const QDateTime &sourceTimeStamp, QString *errorString);
-
- static QString localCacheFilePath(const QUrl &url);
-
-protected:
- quint32 totalStringCount() const
- { return data->stringTableSize; }
-
-#else // V4_BOOTSTRAP
- QString stringAt(int index) const { return data->stringAtInternal(index); }
-#endif // V4_BOOTSTRAP
-
-private:
- void destroy();
-
- struct ResolveSetEntry
- {
- ResolveSetEntry() {}
- ResolveSetEntry(CompilationUnit *module, QV4::String *exportName)
- : module(module), exportName(exportName) {}
- CompilationUnit *module = nullptr;
- QV4::String *exportName = nullptr;
- };
-
- const Value *resolveExportRecursively(QV4::String *exportName, QVector<ResolveSetEntry> *resolveSet);
- const ExportEntry *lookupNameInExportTable(const ExportEntry *firstExportEntry, int tableSize, QV4::String *name) const;
- void getExportedNamesRecursively(QStringList *names, QVector<const CompilationUnit *> *exportNameSet, bool includeDefaultExport = true) const;
-
- QString m_fileName; // initialized from data->sourceFileIndex
- QString m_finalUrlString; // initialized from data->finalUrlIndex
-
- QAtomicInt refCount = 1;
-
- Q_NEVER_INLINE IdentifierHash createNamedObjectsPerComponent(int componentObjectIndex);
-
- Heap::Module *m_module = nullptr;
-
-public:
-#if defined(V4_BOOTSTRAP)
- bool saveToDisk(const QString &outputFileName, QString *errorString);
-#else
- bool saveToDisk(const QUrl &unitUrl, QString *errorString);
-#endif
-};
-
-#ifndef V4_BOOTSTRAP
-struct ResolvedTypeReference
-{
- ResolvedTypeReference()
- : 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;
-
- QQmlRefPointer<QQmlPropertyCache> propertyCache() const;
- QQmlRefPointer<QQmlPropertyCache> createPropertyCache(QQmlEngine *);
- bool addToHash(QCryptographicHash *hash, QQmlEngine *engine);
-
- void doDynamicTypeCheck();
-};
-
-IdentifierHash CompilationUnit::namedObjectsPerComponent(int componentObjectIndex)
-{
- auto it = namedObjectsPerComponentCache.find(componentObjectIndex);
- if (Q_UNLIKELY(it == namedObjectsPerComponentCache.end()))
- return createNamedObjectsPerComponent(componentObjectIndex);
- return *it;
-}
-#endif // V4_BOOTSTRAP
-
-} // CompiledData namespace
-} // QV4 namespace
-
-Q_DECLARE_TYPEINFO(QV4::CompiledData::JSClassMember, Q_PRIMITIVE_TYPE);
-
-QT_END_NAMESPACE
-
-#endif
diff --git a/src/qml/compiler/qv4compiler.cpp b/src/qml/compiler/qv4compiler.cpp
index 01c033cb2a..acc4b02e96 100644
--- a/src/qml/compiler/qv4compiler.cpp
+++ b/src/qml/compiler/qv4compiler.cpp
@@ -38,16 +38,24 @@
****************************************************************************/
#include <qv4compiler_p.h>
-#include <qv4compileddata_p.h>
#include <qv4codegen_p.h>
-#include <private/qv4string_p.h>
-#include <private/qv4value_p.h>
+#include <private/qv4compileddata_p.h>
+#include <private/qv4staticvalue_p.h>
#include <private/qv4alloca_p.h>
#include <private/qqmljslexer_p.h>
#include <private/qqmljsast_p.h>
-#include <wtf/MathExtras.h>
+#include <private/qml_compile_hash_p.h>
+#include <private/qqmlirbuilder_p.h>
#include <QCryptographicHash>
+// Efficient implementation that takes advantage of powers of two.
+static inline size_t roundUpToMultipleOf(size_t divisor, size_t x)
+{
+ Q_ASSERT(divisor && !(divisor & (divisor - 1)));
+ const size_t remainderMask = divisor - 1;
+ return (x + remainderMask) & ~remainderMask;
+}
+
QV4::Compiler::StringTableGenerator::StringTableGenerator()
{
clear();
@@ -92,7 +100,7 @@ void QV4::Compiler::StringTableGenerator::serialize(CompiledData::Unit *unit)
{
char *dataStart = reinterpret_cast<char *>(unit);
quint32_le *stringTable = reinterpret_cast<quint32_le *>(dataStart + unit->offsetToStringTable);
- char *stringData = reinterpret_cast<char *>(stringTable) + WTF::roundUpToMultipleOf(8, unit->stringTableSize * sizeof(uint));
+ char *stringData = reinterpret_cast<char *>(stringTable) + roundUpToMultipleOf(8, unit->stringTableSize * sizeof(uint));
for (int i = backingUnitTableSize ; i < strings.size(); ++i) {
const int index = i - backingUnitTableSize;
stringTable[index] = stringData - dataStart;
@@ -119,6 +127,25 @@ void QV4::Compiler::StringTableGenerator::serialize(CompiledData::Unit *unit)
}
}
+void QV4::Compiler::JSUnitGenerator::generateUnitChecksum(QV4::CompiledData::Unit *unit)
+{
+#ifndef QT_CRYPTOGRAPHICHASH_ONLY_SHA1
+ QCryptographicHash hash(QCryptographicHash::Md5);
+
+ const int checksummableDataOffset
+ = offsetof(QV4::CompiledData::Unit, md5Checksum) + sizeof(unit->md5Checksum);
+
+ const char *dataPtr = reinterpret_cast<const char *>(unit) + checksummableDataOffset;
+ hash.addData(dataPtr, unit->unitSize - checksummableDataOffset);
+
+ QByteArray checksum = hash.result();
+ Q_ASSERT(checksum.size() == sizeof(unit->md5Checksum));
+ memcpy(unit->md5Checksum, checksum.constData(), sizeof(unit->md5Checksum));
+#else
+ memset(unit->md5Checksum, 0, sizeof(unit->md5Checksum));
+#endif
+}
+
QV4::Compiler::JSUnitGenerator::JSUnitGenerator(QV4::Compiler::Module *module)
: module(module)
{
@@ -242,8 +269,11 @@ QV4::CompiledData::Unit *QV4::Compiler::JSUnitGenerator::generateUnit(GeneratorO
registerString(module->finalUrl);
for (Context *f : qAsConst(module->functions)) {
registerString(f->name);
- for (int i = 0; i < f->arguments.size(); ++i)
- registerString(f->arguments.at(i));
+ registerString(f->returnType);
+ for (int i = 0; i < f->arguments.size(); ++i) {
+ registerString(f->arguments.at(i).id);
+ registerString(f->arguments.at(i).typeName());
+ }
for (int i = 0; i < f->locals.size(); ++i)
registerString(f->locals.at(i));
}
@@ -385,7 +415,7 @@ QV4::CompiledData::Unit *QV4::Compiler::JSUnitGenerator::generateUnit(GeneratorO
if (option == GenerateWithStringTable)
stringTable.serialize(unit);
- unit->generateChecksum();
+ generateUnitChecksum(unit);
return unit;
}
@@ -394,7 +424,7 @@ void QV4::Compiler::JSUnitGenerator::writeFunction(char *f, QV4::Compiler::Conte
{
QV4::CompiledData::Function *function = (QV4::CompiledData::Function *)f;
- quint32 currentOffset = static_cast<quint32>(WTF::roundUpToMultipleOf(8, sizeof(*function)));
+ quint32 currentOffset = static_cast<quint32>(roundUpToMultipleOf(8, sizeof(*function)));
function->nameIndex = getStringId(irFunction->name);
function->flags = 0;
@@ -410,7 +440,9 @@ void QV4::Compiler::JSUnitGenerator::writeFunction(char *f, QV4::Compiler::Conte
function->length = irFunction->formals ? irFunction->formals->length() : 0;
function->nFormals = irFunction->arguments.size();
function->formalsOffset = currentOffset;
- currentOffset += function->nFormals * sizeof(quint32);
+ currentOffset += function->nFormals * sizeof(CompiledData::Parameter);
+
+ QmlIR::Parameter::initType(&function->returnType, this, getStringId(irFunction->returnType));
function->sizeOfLocalTemporalDeadZone = irFunction->sizeOfLocalTemporalDeadZone;
function->sizeOfRegisterTemporalDeadZone = irFunction->sizeOfRegisterTemporalDeadZone;
@@ -424,7 +456,6 @@ void QV4::Compiler::JSUnitGenerator::writeFunction(char *f, QV4::Compiler::Conte
Q_ASSERT(function->lineNumberOffset() == currentOffset);
currentOffset += function->nLineNumbers * sizeof(CompiledData::CodeOffsetToLine);
- function->nTraceInfos = irFunction->nTraceInfos;
function->nRegisters = irFunction->registerCountInFunction;
if (!irFunction->labelInfo.empty()) {
@@ -440,9 +471,11 @@ void QV4::Compiler::JSUnitGenerator::writeFunction(char *f, QV4::Compiler::Conte
function->codeSize = irFunction->code.size();
// write formals
- quint32_le *formals = (quint32_le *)(f + function->formalsOffset);
- for (int i = 0; i < irFunction->arguments.size(); ++i)
- formals[i] = getStringId(irFunction->arguments.at(i));
+ CompiledData::Parameter *formals = (CompiledData::Parameter *)(f + function->formalsOffset);
+ for (int i = 0; i < irFunction->arguments.size(); ++i) {
+ QmlIR::Parameter::init(&formals[i], this, getStringId(irFunction->arguments.at(i).id),
+ getStringId(irFunction->arguments.at(i).typeName()));
+ }
// write locals
quint32_le *locals = (quint32_le *)(f + function->localsOffset);
@@ -545,7 +578,7 @@ void QV4::Compiler::JSUnitGenerator::writeBlock(char *b, QV4::Compiler::Context
{
QV4::CompiledData::Block *block = reinterpret_cast<QV4::CompiledData::Block *>(b);
- quint32 currentOffset = static_cast<quint32>(WTF::roundUpToMultipleOf(8, sizeof(*block)));
+ quint32 currentOffset = static_cast<quint32>(roundUpToMultipleOf(8, sizeof(*block)));
block->sizeOfLocalTemporalDeadZone = irBlock->sizeOfLocalTemporalDeadZone;
block->nLocals = irBlock->locals.size();
@@ -575,7 +608,7 @@ QV4::CompiledData::Unit QV4::Compiler::JSUnitGenerator::generateHeader(QV4::Comp
unit.flags |= module->unitFlags;
unit.version = QV4_DATA_STRUCTURE_VERSION;
unit.qtVersion = QT_VERSION;
- qstrcpy(unit.libraryVersionHash, CompiledData::qml_compile_hash);
+ qstrcpy(unit.libraryVersionHash, QML_COMPILE_HASH);
memset(unit.md5Checksum, 0, sizeof(unit.md5Checksum));
memset(unit.dependencyMD5Checksum, 0, sizeof(unit.dependencyMD5Checksum));
@@ -608,7 +641,7 @@ QV4::CompiledData::Unit QV4::Compiler::JSUnitGenerator::generateHeader(QV4::Comp
unit.constantTableSize = constants.size();
// Ensure we load constants from well-aligned addresses into for example SSE registers.
- nextOffset = static_cast<quint32>(WTF::roundUpToMultipleOf(16, nextOffset));
+ nextOffset = static_cast<quint32>(roundUpToMultipleOf(16, nextOffset));
unit.offsetToConstantTable = nextOffset;
nextOffset += unit.constantTableSize * sizeof(ReturnedValue);
@@ -619,19 +652,19 @@ QV4::CompiledData::Unit QV4::Compiler::JSUnitGenerator::generateHeader(QV4::Comp
*jsClassDataOffset = nextOffset;
nextOffset += jsClassData.size();
- nextOffset = static_cast<quint32>(WTF::roundUpToMultipleOf(8, nextOffset));
+ nextOffset = static_cast<quint32>(roundUpToMultipleOf(8, nextOffset));
unit.translationTableSize = translations.count();
unit.offsetToTranslationTable = nextOffset;
nextOffset += unit.translationTableSize * sizeof(CompiledData::TranslationData);
- nextOffset = static_cast<quint32>(WTF::roundUpToMultipleOf(8, nextOffset));
+ nextOffset = static_cast<quint32>(roundUpToMultipleOf(8, nextOffset));
const auto reserveExportTable = [&nextOffset](int count, quint32_le *tableSizePtr, quint32_le *offsetPtr) {
*tableSizePtr = count;
*offsetPtr = nextOffset;
nextOffset += count * sizeof(CompiledData::ExportEntry);
- nextOffset = static_cast<quint32>(WTF::roundUpToMultipleOf(8, nextOffset));
+ nextOffset = static_cast<quint32>(roundUpToMultipleOf(8, nextOffset));
};
reserveExportTable(module->localExportEntries.count(), &unit.localExportEntryTableSize, &unit.offsetToLocalExportEntryTable);
@@ -641,12 +674,12 @@ QV4::CompiledData::Unit QV4::Compiler::JSUnitGenerator::generateHeader(QV4::Comp
unit.importEntryTableSize = module->importEntries.count();
unit.offsetToImportEntryTable = nextOffset;
nextOffset += unit.importEntryTableSize * sizeof(CompiledData::ImportEntry);
- nextOffset = static_cast<quint32>(WTF::roundUpToMultipleOf(8, nextOffset));
+ nextOffset = static_cast<quint32>(roundUpToMultipleOf(8, nextOffset));
unit.moduleRequestTableSize = module->moduleRequests.count();
unit.offsetToModuleRequestTable = nextOffset;
nextOffset += unit.moduleRequestTableSize * sizeof(uint);
- nextOffset = static_cast<quint32>(WTF::roundUpToMultipleOf(8, nextOffset));
+ nextOffset = static_cast<quint32>(roundUpToMultipleOf(8, nextOffset));
quint32 functionSize = 0;
for (int i = 0; i < module->functions.size(); ++i) {
@@ -686,7 +719,7 @@ QV4::CompiledData::Unit QV4::Compiler::JSUnitGenerator::generateHeader(QV4::Comp
if (option == GenerateWithStringTable) {
unit.stringTableSize = stringTable.stringCount();
- nextOffset = static_cast<quint32>(WTF::roundUpToMultipleOf(8, nextOffset));
+ nextOffset = static_cast<quint32>(roundUpToMultipleOf(8, nextOffset));
unit.offsetToStringTable = nextOffset;
nextOffset += stringTable.sizeOfTableAndData();
} else {
diff --git a/src/qml/compiler/qv4compiler_p.h b/src/qml/compiler/qv4compiler_p.h
index 49e334bb81..4f3c718175 100644
--- a/src/qml/compiler/qv4compiler_p.h
+++ b/src/qml/compiler/qv4compiler_p.h
@@ -53,9 +53,10 @@
#include <QtCore/qstring.h>
#include <QtCore/qhash.h>
#include <QtCore/qstringlist.h>
-#include <private/qv4global_p.h>
+#include <private/qv4compilerglobal_p.h>
#include <private/qqmljsastfwd_p.h>
#include <private/qv4compileddata_p.h>
+#include <private/qv4staticvalue_p.h>
QT_BEGIN_NAMESPACE
@@ -72,10 +73,12 @@ struct JSClassMember;
namespace Compiler {
+struct Context;
+struct Module;
struct Class;
struct TemplateObject;
-struct Q_QML_PRIVATE_EXPORT StringTableGenerator {
+struct Q_QMLCOMPILER_PRIVATE_EXPORT StringTableGenerator {
StringTableGenerator();
int registerString(const QString &str);
@@ -102,7 +105,9 @@ private:
bool frozen = false;
};
-struct Q_QML_PRIVATE_EXPORT JSUnitGenerator {
+struct Q_QMLCOMPILER_PRIVATE_EXPORT JSUnitGenerator {
+ static void generateUnitChecksum(CompiledData::Unit *unit);
+
struct MemberInfo {
QString name;
bool isAccessor;
diff --git a/src/qml/compiler/qv4compilercontext.cpp b/src/qml/compiler/qv4compilercontext.cpp
index ca2d5128f4..88837b0feb 100644
--- a/src/qml/compiler/qv4compilercontext.cpp
+++ b/src/qml/compiler/qv4compilercontext.cpp
@@ -156,7 +156,7 @@ Context::ResolvedName Context::resolveName(const QString &name, const QQmlJS::AS
result.isConst = false;
return result;
} else {
- result.index = argIdx + sizeof(CallData)/sizeof(Value) - 1;
+ result.index = argIdx + sizeof(CallData) / sizeof(StaticValue) - 1;
result.scope = 0;
result.type = ResolvedName::Stack;
result.isConst = false;
@@ -410,28 +410,4 @@ void Context::setupFunctionIndices(Moth::BytecodeGenerator *bytecodeGenerator)
nRegisters = bytecodeGenerator->currentRegister() - registerOffset;
}
-bool Context::canUseTracingJit() const
-{
-#if QT_CONFIG(qml_tracing)
- static bool forceTracing = !qEnvironmentVariableIsEmpty("QV4_FORCE_TRACING");
- if (forceTracing) //### we can probably remove this when tracing is turned on by default
- return true; // to be used by unittests
-
- static bool disableTracing = !qEnvironmentVariableIsEmpty("QV4_DISABLE_TRACING");
- if (disableTracing)
- return false;
-
- static QStringList onlyTrace =
- qEnvironmentVariable("QV4_ONLY_TRACE").split(QLatin1Char(','), QString::SkipEmptyParts);
- if (!onlyTrace.isEmpty())
- return onlyTrace.contains(name);
-
- //### the next condition should be refined and have the IR distinguish between escaping and
- // non-escaping locals
- return !requiresExecutionContext && !hasNestedFunctions;
-#else
- return false;
-#endif
-}
-
QT_END_NAMESPACE
diff --git a/src/qml/compiler/qv4compilercontext_p.h b/src/qml/compiler/qv4compilercontext_p.h
index 57ef4be36e..8c124ac409 100644
--- a/src/qml/compiler/qv4compilercontext_p.h
+++ b/src/qml/compiler/qv4compilercontext_p.h
@@ -50,7 +50,6 @@
// We mean it.
//
-#include "private/qv4global_p.h"
#include <private/qqmljsast_p.h>
#include <private/qv4compileddata_p.h>
#include <QtCore/QStringList>
@@ -62,8 +61,13 @@ QT_BEGIN_NAMESPACE
namespace QV4 {
+namespace Moth {
+class BytecodeGenerator;
+}
+
namespace Compiler {
+class Codegen;
struct ControlFlow;
enum class ContextType {
@@ -162,7 +166,6 @@ struct Context {
int line = 0;
int column = 0;
int registerCountInFunction = 0;
- uint nTraceInfos = 0;
int functionIndex = -1;
int blockIndex = -1;
@@ -190,7 +193,8 @@ struct Context {
MemberMap members;
QSet<QString> usedVariables;
QQmlJS::AST::FormalParameterList *formals = nullptr;
- QStringList arguments;
+ QQmlJS::AST::BoundNames arguments;
+ QString returnType;
QStringList locals;
QStringList moduleRequests;
QVector<ImportEntry> importEntries;
@@ -289,7 +293,7 @@ struct Context {
{
// search backwards to handle duplicate argument names correctly
for (int i = arguments.size() - 1; i >= 0; --i) {
- if (arguments.at(i) == name)
+ if (arguments.at(i).id == name)
return i;
}
return -1;
@@ -363,8 +367,6 @@ struct Context {
return parent->canHaveTailCalls();
return false;
}
-
- bool canUseTracingJit() const;
};
diff --git a/src/qml/compiler/qv4compilercontrolflow_p.h b/src/qml/compiler/qv4compilercontrolflow_p.h
index 5b622e81d8..5623473726 100644
--- a/src/qml/compiler/qv4compilercontrolflow_p.h
+++ b/src/qml/compiler/qv4compilercontrolflow_p.h
@@ -50,7 +50,6 @@
// We mean it.
//
-#include <private/qv4global_p.h>
#include <private/qv4codegen_p.h>
#include <private/qqmljsast_p.h>
#include <private/qv4bytecodegenerator_p.h>
@@ -279,7 +278,7 @@ struct ControlFlowWith : public ControlFlowUnwind
struct ControlFlowBlock : public ControlFlowUnwind
{
- ControlFlowBlock(Codegen *cg, AST::Node *ast)
+ ControlFlowBlock(Codegen *cg, QQmlJS::AST::Node *ast)
: ControlFlowUnwind(cg, Block)
{
block = cg->enterBlock(ast);
@@ -314,11 +313,11 @@ struct ControlFlowBlock : public ControlFlowUnwind
struct ControlFlowCatch : public ControlFlowUnwind
{
- AST::Catch *catchExpression;
+ QQmlJS::AST::Catch *catchExpression;
bool insideCatch = false;
BytecodeGenerator::ExceptionHandler exceptionLabel;
- ControlFlowCatch(Codegen *cg, AST::Catch *catchExpression)
+ ControlFlowCatch(Codegen *cg, QQmlJS::AST::Catch *catchExpression)
: ControlFlowUnwind(cg, Catch), catchExpression(catchExpression),
exceptionLabel(generator()->newExceptionHandler())
{
@@ -372,10 +371,10 @@ struct ControlFlowCatch : public ControlFlowUnwind
struct ControlFlowFinally : public ControlFlowUnwind
{
- AST::Finally *finally;
+ QQmlJS::AST::Finally *finally;
bool insideFinally = false;
- ControlFlowFinally(Codegen *cg, AST::Finally *finally)
+ ControlFlowFinally(Codegen *cg, QQmlJS::AST::Finally *finally)
: ControlFlowUnwind(cg, Finally), finally(finally)
{
Q_ASSERT(finally != nullptr);
diff --git a/src/qml/compiler/qv4compilationunitmapper_p.h b/src/qml/compiler/qv4compilerglobal_p.h
index 80f914c141..3478074827 100644
--- a/src/qml/compiler/qv4compilationunitmapper_p.h
+++ b/src/qml/compiler/qv4compilerglobal_p.h
@@ -1,6 +1,6 @@
/****************************************************************************
**
-** Copyright (C) 2016 The Qt Company Ltd.
+** Copyright (C) 2019 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of the QtQml module of the Qt Toolkit.
@@ -37,8 +37,8 @@
**
****************************************************************************/
-#ifndef QV4COMPILATIONUNITMAPPER_H
-#define QV4COMPILATIONUNITMAPPER_H
+#ifndef QV4COMPILERGLOBAL_H
+#define QV4COMPILERGLOBAL_H
//
// W A R N I N G
@@ -51,35 +51,24 @@
// We mean it.
//
-#include <private/qv4global_p.h>
-#include <QFile>
+#include <QtCore/qglobal.h>
+#include <QString>
+
+#include <private/qtqmlcompilerglobal_p.h>
QT_BEGIN_NAMESPACE
namespace QV4 {
-namespace CompiledData {
-struct Unit;
-}
-
-class CompilationUnitMapper
-{
-public:
- CompilationUnitMapper();
- ~CompilationUnitMapper();
-
- CompiledData::Unit *open(const QString &cacheFilePath, const QDateTime &sourceTimeStamp, QString *errorString);
- void close();
-
-private:
-#if defined(Q_OS_UNIX)
- size_t length;
-#endif
- void *dataPtr;
+enum class ObjectLiteralArgument {
+ Value,
+ Method,
+ Getter,
+ Setter
};
-}
+} // namespace QV4
QT_END_NAMESPACE
-#endif // QV4COMPILATIONUNITMAPPER_H
+#endif // QV4COMPILERGLOBAL_H
diff --git a/src/qml/compiler/qv4compilerscanfunctions.cpp b/src/qml/compiler/qv4compilerscanfunctions.cpp
index 8984b6931e..ab0ebf3d4b 100644
--- a/src/qml/compiler/qv4compilerscanfunctions.cpp
+++ b/src/qml/compiler/qv4compilerscanfunctions.cpp
@@ -44,18 +44,26 @@
#include <QtCore/QSet>
#include <QtCore/QBuffer>
#include <QtCore/QBitArray>
-#include <QtCore/QLinkedList>
#include <QtCore/QStack>
#include <private/qqmljsast_p.h>
#include <private/qv4compilercontext_p.h>
#include <private/qv4codegen_p.h>
-#include <private/qv4string_p.h>
QT_USE_NAMESPACE
using namespace QV4;
using namespace QV4::Compiler;
+using namespace QQmlJS;
using namespace QQmlJS::AST;
+static CompiledData::Location location(const QQmlJS::AST::SourceLocation &astLocation)
+{
+ CompiledData::Location target;
+ target.line = astLocation.startLine;
+ target.column = astLocation.startColumn;
+ return target;
+}
+
+
ScanFunctions::ScanFunctions(Codegen *cg, const QString &sourceCode, ContextType defaultProgramType)
: QQmlJS::AST::Visitor(cg->recursionDepth())
, _cg(cg)
@@ -177,7 +185,7 @@ bool ScanFunctions::visit(ExportDeclaration *declaration)
Compiler::ExportEntry entry;
entry.moduleRequest = declaration->fromClause->moduleSpecifier.toString();
entry.importName = QStringLiteral("*");
- entry.location = declaration->firstSourceLocation();
+ entry.location = location(declaration->firstSourceLocation());
_context->exportEntries << entry;
} else if (declaration->exportClause) {
for (ExportsList *it = declaration->exportClause->exportsList; it; it = it->next) {
@@ -190,22 +198,22 @@ bool ScanFunctions::visit(ExportDeclaration *declaration)
entry.moduleRequest = module;
entry.exportName = spec->exportedIdentifier.toString();
- entry.location = it->firstSourceLocation();
+ entry.location = location(it->firstSourceLocation());
_context->exportEntries << entry;
}
} else if (auto *vstmt = AST::cast<AST::VariableStatement*>(declaration->variableStatementOrDeclaration)) {
- QStringList boundNames;
+ BoundNames boundNames;
for (VariableDeclarationList *it = vstmt->declarations; it; it = it->next) {
if (!it->declaration)
continue;
it->declaration->boundNames(&boundNames);
}
- for (const QString &name: boundNames) {
+ for (const auto &name: boundNames) {
Compiler::ExportEntry entry;
- entry.localName = name;
- entry.exportName = name;
- entry.location = vstmt->firstSourceLocation();
+ entry.localName = name.id;
+ entry.exportName = name.id;
+ entry.location = location(vstmt->firstSourceLocation());
_context->exportEntries << entry;
}
} else if (auto *classDecl = AST::cast<AST::ClassDeclaration*>(declaration->variableStatementOrDeclaration)) {
@@ -214,7 +222,7 @@ bool ScanFunctions::visit(ExportDeclaration *declaration)
Compiler::ExportEntry entry;
entry.localName = name;
entry.exportName = name;
- entry.location = classDecl->firstSourceLocation();
+ entry.location = location(classDecl->firstSourceLocation());
_context->exportEntries << entry;
if (declaration->exportDefault)
localNameForDefaultExport = entry.localName;
@@ -233,7 +241,7 @@ bool ScanFunctions::visit(ExportDeclaration *declaration)
Compiler::ExportEntry entry;
entry.localName = functionName;
entry.exportName = functionName;
- entry.location = fdef->firstSourceLocation();
+ entry.location = location(fdef->firstSourceLocation());
_context->exportEntries << entry;
if (declaration->exportDefault)
localNameForDefaultExport = entry.localName;
@@ -245,7 +253,7 @@ bool ScanFunctions::visit(ExportDeclaration *declaration)
entry.localName = localNameForDefaultExport;
_context->localNameForDefaultExport = localNameForDefaultExport;
entry.exportName = QStringLiteral("default");
- entry.location = declaration->firstSourceLocation();
+ entry.location = location(declaration->firstSourceLocation());
_context->exportEntries << entry;
}
@@ -270,7 +278,7 @@ bool ScanFunctions::visit(ImportDeclaration *declaration)
entry.moduleRequest = module;
entry.importName = QStringLiteral("default");
entry.localName = import->importedDefaultBinding.toString();
- entry.location = declaration->firstSourceLocation();
+ entry.location = location(declaration->firstSourceLocation());
_context->importEntries << entry;
}
@@ -279,7 +287,7 @@ bool ScanFunctions::visit(ImportDeclaration *declaration)
entry.moduleRequest = module;
entry.importName = QStringLiteral("*");
entry.localName = import->nameSpaceImport->importedBinding.toString();
- entry.location = declaration->firstSourceLocation();
+ entry.location = location(declaration->firstSourceLocation());
_context->importEntries << entry;
}
@@ -292,7 +300,7 @@ bool ScanFunctions::visit(ImportDeclaration *declaration)
entry.importName = it->importSpecifier->identifier.toString();
else
entry.importName = entry.localName;
- entry.location = declaration->firstSourceLocation();
+ entry.location = location(declaration->firstSourceLocation());
_context->importEntries << entry;
}
}
@@ -319,26 +327,26 @@ bool ScanFunctions::visit(PatternElement *ast)
if (!ast->isVariableDeclaration())
return true;
- QStringList names;
+ BoundNames names;
ast->boundNames(&names);
QQmlJS::AST::SourceLocation lastInitializerLocation = ast->lastSourceLocation();
if (_context->lastBlockInitializerLocation.isValid())
lastInitializerLocation = _context->lastBlockInitializerLocation;
- for (const QString &name : qAsConst(names)) {
- if (_context->isStrict && (name == QLatin1String("eval") || name == QLatin1String("arguments")))
+ for (const auto &name : qAsConst(names)) {
+ if (_context->isStrict && (name.id == QLatin1String("eval") || name.id == QLatin1String("arguments")))
_cg->throwSyntaxError(ast->identifierToken, QStringLiteral("Variable name may not be eval or arguments in strict mode"));
- checkName(QStringRef(&name), ast->identifierToken);
- if (name == QLatin1String("arguments"))
+ checkName(QStringRef(&name.id), ast->identifierToken);
+ if (name.id == QLatin1String("arguments"))
_context->usesArgumentsObject = Context::ArgumentsObjectNotUsed;
if (ast->scope == VariableScope::Const && !ast->initializer && !ast->isForDeclaration && !ast->destructuringPattern()) {
_cg->throwSyntaxError(ast->identifierToken, QStringLiteral("Missing initializer in const declaration"));
return false;
}
- if (!_context->addLocalVar(name, ast->initializer ? Context::VariableDefinition : Context::VariableDeclaration, ast->scope,
+ if (!_context->addLocalVar(name.id, ast->initializer ? Context::VariableDefinition : Context::VariableDeclaration, ast->scope,
/*function*/nullptr, lastInitializerLocation)) {
- _cg->throwSyntaxError(ast->identifierToken, QStringLiteral("Identifier %1 has already been declared").arg(name));
+ _cg->throwSyntaxError(ast->identifierToken, QStringLiteral("Identifier %1 has already been declared").arg(name.id));
return false;
}
}
@@ -672,6 +680,9 @@ bool ScanFunctions::enterFunction(Node *ast, const QString &name, FormalParamete
_context->isArrowFunction = true;
else if (expr->isGenerator)
_context->isGenerator = true;
+
+ if (expr->typeAnnotation)
+ _context->returnType = expr->typeAnnotation->type->toString();
}
@@ -684,11 +695,11 @@ bool ScanFunctions::enterFunction(Node *ast, const QString &name, FormalParamete
bool isSimpleParameterList = formals && formals->isSimpleParameterList();
- _context->arguments = formals ? formals->formals() : QStringList();
+ _context->arguments = formals ? formals->formals() : BoundNames();
- const QStringList boundNames = formals ? formals->boundNames() : QStringList();
+ const BoundNames boundNames = formals ? formals->boundNames() : BoundNames();
for (int i = 0; i < boundNames.size(); ++i) {
- const QString &arg = boundNames.at(i);
+ const QString &arg = boundNames.at(i).id;
if (_context->isStrict || !isSimpleParameterList) {
bool duplicate = (boundNames.indexOf(arg, i + 1) != -1);
if (duplicate) {
@@ -705,6 +716,7 @@ bool ScanFunctions::enterFunction(Node *ast, const QString &name, FormalParamete
if (!_context->arguments.contains(arg))
_context->addLocalVar(arg, Context::VariableDefinition, VariableScope::Var);
}
+
return true;
}
diff --git a/src/qml/compiler/qv4compilerscanfunctions_p.h b/src/qml/compiler/qv4compilerscanfunctions_p.h
index 0f7bf1818a..2de80eac44 100644
--- a/src/qml/compiler/qv4compilerscanfunctions_p.h
+++ b/src/qml/compiler/qv4compilerscanfunctions_p.h
@@ -50,7 +50,7 @@
// We mean it.
//
-#include "private/qv4global_p.h"
+#include <private/qtqmlcompilerglobal_p.h>
#include <private/qqmljsastvisitor_p.h>
#include <private/qqmljsast_p.h>
#include <private/qqmljsengine_p.h>
@@ -62,8 +62,6 @@
QT_BEGIN_NAMESPACE
-using namespace QQmlJS;
-
namespace QV4 {
namespace Moth {
@@ -83,84 +81,87 @@ class ScanFunctions: protected QQmlJS::AST::Visitor
typedef QScopedValueRollback<bool> TemporaryBoolAssignment;
public:
ScanFunctions(Codegen *cg, const QString &sourceCode, ContextType defaultProgramType);
- void operator()(AST::Node *node);
+ void operator()(QQmlJS::AST::Node *node);
void enterGlobalEnvironment(ContextType compilationMode);
- void enterEnvironment(AST::Node *node, ContextType compilationMode, const QString &name);
+ void enterEnvironment(QQmlJS::AST::Node *node, ContextType compilationMode,
+ const QString &name);
void leaveEnvironment();
- void enterQmlFunction(AST::FunctionDeclaration *ast)
+ void enterQmlFunction(QQmlJS::AST::FunctionExpression *ast)
{ enterFunction(ast, false); }
protected:
using Visitor::visit;
using Visitor::endVisit;
- void checkDirectivePrologue(AST::StatementList *ast);
+ void checkDirectivePrologue(QQmlJS::AST::StatementList *ast);
- void checkName(const QStringRef &name, const AST::SourceLocation &loc);
+ void checkName(const QStringRef &name, const QQmlJS::AST::SourceLocation &loc);
- bool visit(AST::Program *ast) override;
- void endVisit(AST::Program *) override;
+ bool visit(QQmlJS::AST::Program *ast) override;
+ void endVisit(QQmlJS::AST::Program *) override;
- bool visit(AST::ESModule *ast) override;
- void endVisit(AST::ESModule *) override;
+ bool visit(QQmlJS::AST::ESModule *ast) override;
+ void endVisit(QQmlJS::AST::ESModule *) override;
- bool visit(AST::ExportDeclaration *declaration) override;
- bool visit(AST::ImportDeclaration *declaration) override;
+ bool visit(QQmlJS::AST::ExportDeclaration *declaration) override;
+ bool visit(QQmlJS::AST::ImportDeclaration *declaration) override;
- bool visit(AST::CallExpression *ast) override;
- bool visit(AST::PatternElement *ast) override;
- bool visit(AST::IdentifierExpression *ast) override;
- bool visit(AST::ExpressionStatement *ast) override;
- bool visit(AST::FunctionExpression *ast) override;
- bool visit(AST::TemplateLiteral *ast) override;
- bool visit(AST::SuperLiteral *) override;
- bool visit(AST::FieldMemberExpression *) override;
- bool visit(AST::ArrayPattern *) override;
+ bool visit(QQmlJS::AST::CallExpression *ast) override;
+ bool visit(QQmlJS::AST::PatternElement *ast) override;
+ bool visit(QQmlJS::AST::IdentifierExpression *ast) override;
+ bool visit(QQmlJS::AST::ExpressionStatement *ast) override;
+ bool visit(QQmlJS::AST::FunctionExpression *ast) override;
+ bool visit(QQmlJS::AST::TemplateLiteral *ast) override;
+ bool visit(QQmlJS::AST::SuperLiteral *) override;
+ bool visit(QQmlJS::AST::FieldMemberExpression *) override;
+ bool visit(QQmlJS::AST::ArrayPattern *) override;
- bool enterFunction(AST::FunctionExpression *ast, bool enterName);
+ bool enterFunction(QQmlJS::AST::FunctionExpression *ast, bool enterName);
- void endVisit(AST::FunctionExpression *) override;
+ void endVisit(QQmlJS::AST::FunctionExpression *) override;
- bool visit(AST::ObjectPattern *ast) override;
+ bool visit(QQmlJS::AST::ObjectPattern *ast) override;
- bool visit(AST::PatternProperty *ast) override;
- void endVisit(AST::PatternProperty *) override;
+ bool visit(QQmlJS::AST::PatternProperty *ast) override;
+ void endVisit(QQmlJS::AST::PatternProperty *) override;
- bool visit(AST::FunctionDeclaration *ast) override;
- void endVisit(AST::FunctionDeclaration *) override;
+ bool visit(QQmlJS::AST::FunctionDeclaration *ast) override;
+ void endVisit(QQmlJS::AST::FunctionDeclaration *) override;
- bool visit(AST::ClassExpression *ast) override;
- void endVisit(AST::ClassExpression *) override;
+ bool visit(QQmlJS::AST::ClassExpression *ast) override;
+ void endVisit(QQmlJS::AST::ClassExpression *) override;
- bool visit(AST::ClassDeclaration *ast) override;
- void endVisit(AST::ClassDeclaration *) override;
+ bool visit(QQmlJS::AST::ClassDeclaration *ast) override;
+ void endVisit(QQmlJS::AST::ClassDeclaration *) override;
- bool visit(AST::DoWhileStatement *ast) override;
- bool visit(AST::ForStatement *ast) override;
- void endVisit(AST::ForStatement *) override;
- bool visit(AST::ForEachStatement *ast) override;
- void endVisit(AST::ForEachStatement *) override;
+ bool visit(QQmlJS::AST::DoWhileStatement *ast) override;
+ bool visit(QQmlJS::AST::ForStatement *ast) override;
+ void endVisit(QQmlJS::AST::ForStatement *) override;
+ bool visit(QQmlJS::AST::ForEachStatement *ast) override;
+ void endVisit(QQmlJS::AST::ForEachStatement *) override;
- bool visit(AST::ThisExpression *ast) override;
+ bool visit(QQmlJS::AST::ThisExpression *ast) override;
- bool visit(AST::Block *ast) override;
- void endVisit(AST::Block *ast) override;
+ bool visit(QQmlJS::AST::Block *ast) override;
+ void endVisit(QQmlJS::AST::Block *ast) override;
- bool visit(AST::CaseBlock *ast) override;
- void endVisit(AST::CaseBlock *ast) override;
+ bool visit(QQmlJS::AST::CaseBlock *ast) override;
+ void endVisit(QQmlJS::AST::CaseBlock *ast) override;
- bool visit(AST::Catch *ast) override;
- void endVisit(AST::Catch *ast) override;
+ bool visit(QQmlJS::AST::Catch *ast) override;
+ void endVisit(QQmlJS::AST::Catch *ast) override;
- bool visit(AST::WithStatement *ast) override;
- void endVisit(AST::WithStatement *ast) override;
+ bool visit(QQmlJS::AST::WithStatement *ast) override;
+ void endVisit(QQmlJS::AST::WithStatement *ast) override;
void throwRecursionDepthError() override;
protected:
- bool enterFunction(AST::Node *ast, const QString &name, AST::FormalParameterList *formals, AST::StatementList *body, bool enterName);
+ bool enterFunction(QQmlJS::AST::Node *ast, const QString &name,
+ QQmlJS::AST::FormalParameterList *formals,
+ QQmlJS::AST::StatementList *body, bool enterName);
void calcEscapingVariables();
// fields:
@@ -173,7 +174,7 @@ protected:
ContextType defaultProgramType;
private:
- static constexpr AST::Node *astNodeForGlobalEnvironment = nullptr;
+ static constexpr QQmlJS::AST::Node *astNodeForGlobalEnvironment = nullptr;
};
}
diff --git a/src/qml/compiler/qv4instr_moth.cpp b/src/qml/compiler/qv4instr_moth.cpp
index 345f03ae8a..640a908dd3 100644
--- a/src/qml/compiler/qv4instr_moth.cpp
+++ b/src/qml/compiler/qv4instr_moth.cpp
@@ -39,7 +39,9 @@
#include "qv4instr_moth_p.h"
#include <private/qv4compileddata_p.h>
-#include <private/qv4stackframe_p.h>
+#include <private/qv4calldata_p.h>
+
+#include <QtCore/qdebug.h>
using namespace QV4;
using namespace QV4::Moth;
@@ -56,9 +58,7 @@ int InstrInfo::size(Instr::Type type)
static QByteArray alignedNumber(int n) {
QByteArray number = QByteArray::number(n);
- while (number.size() < 8)
- number.prepend(' ');
- return number;
+ return number.prepend(8 - number.size(), ' ');
}
static QByteArray alignedLineNumber(int line) {
@@ -83,25 +83,6 @@ static QByteArray rawBytes(const char *data, int n)
return ba;
}
-static QString toString(QV4::ReturnedValue v)
-{
-#ifdef V4_BOOTSTRAP
- return QStringLiteral("string-const(%1)").arg(v);
-#else // !V4_BOOTSTRAP
- Value val = Value::fromReturnedValue(v);
- QString result;
- if (val.isInt32())
- result = QLatin1String("int ");
- else if (val.isDouble())
- result = QLatin1String("double ");
- if (val.isEmpty())
- result += QLatin1String("empty");
- else
- result += val.toQStringNoThrow();
- return result;
-#endif // V4_BOOTSTRAP
-}
-
#define ABSOLUTE_OFFSET() \
(code - start + offset)
@@ -128,22 +109,12 @@ const int InstrInfo::argumentCount[] = {
FOR_EACH_MOTH_INSTR_ALL(MOTH_COLLECT_NARGS)
};
-
-void dumpConstantTable(const Value *constants, uint count)
-{
- QDebug d = qDebug();
- d.nospace();
- for (uint i = 0; i < count; ++i)
- d << alignedNumber(int(i)).constData() << ": "
- << toString(constants[i].asReturnedValue()).toUtf8().constData() << "\n";
-}
-
QString dumpRegister(int reg, int nFormals)
{
Q_STATIC_ASSERT(offsetof(CallData, function) == 0);
- Q_STATIC_ASSERT(offsetof(CallData, context) == sizeof(Value));
- Q_STATIC_ASSERT(offsetof(CallData, accumulator) == 2*sizeof(Value));
- Q_STATIC_ASSERT(offsetof(CallData, thisObject) == 3*sizeof(Value));
+ Q_STATIC_ASSERT(offsetof(CallData, context) == sizeof(StaticValue));
+ Q_STATIC_ASSERT(offsetof(CallData, accumulator) == 2*sizeof(StaticValue));
+ Q_STATIC_ASSERT(offsetof(CallData, thisObject) == 3*sizeof(StaticValue));
if (reg == CallData::Function)
return QStringLiteral("(function)");
else if (reg == CallData::Context)
@@ -171,8 +142,6 @@ QString dumpArguments(int argc, int argv, int nFormals)
return QStringLiteral("(") + dumpRegister(argv, nFormals) + QStringLiteral(", ") + QString::number(argc) + QStringLiteral(")");
}
-#define TRACE_SLOT QStringLiteral(" {%1}").arg(traceSlot)
-
void dumpBytecode(const char *code, int len, int nLocals, int nFormals, int /*startLine*/, const QVector<CompiledData::CodeOffsetToLine> &lineNumberMapping)
{
MOTH_JUMP_TABLE;
@@ -241,9 +210,9 @@ void dumpBytecode(const char *code, int len, int nLocals, int nFormals, int /*st
MOTH_BEGIN_INSTR(LoadLocal)
if (index < nLocals)
- d << "l" << index << TRACE_SLOT;
+ d << "l" << index;
else
- d << "a" << (index - nLocals) << TRACE_SLOT;
+ d << "a" << (index - nLocals);
MOTH_END_INSTR(LoadLocal)
MOTH_BEGIN_INSTR(StoreLocal)
@@ -255,9 +224,9 @@ void dumpBytecode(const char *code, int len, int nLocals, int nFormals, int /*st
MOTH_BEGIN_INSTR(LoadScopedLocal)
if (index < nLocals)
- d << "l" << index << "@" << scope << TRACE_SLOT;
+ d << "l" << index << "@" << scope;
else
- d << "a" << (index - nLocals) << "@" << scope << TRACE_SLOT;
+ d << "a" << (index - nLocals) << "@" << scope;
MOTH_END_INSTR(LoadScopedLocal)
MOTH_BEGIN_INSTR(StoreScopedLocal)
@@ -280,15 +249,15 @@ void dumpBytecode(const char *code, int len, int nLocals, int nFormals, int /*st
MOTH_END_INSTR(LoadClosure)
MOTH_BEGIN_INSTR(LoadName)
- d << name << TRACE_SLOT;
+ d << name;
MOTH_END_INSTR(LoadName)
MOTH_BEGIN_INSTR(LoadGlobalLookup)
- d << index << TRACE_SLOT;
+ d << index;
MOTH_END_INSTR(LoadGlobalLookup)
MOTH_BEGIN_INSTR(LoadQmlContextPropertyLookup)
- d << index << TRACE_SLOT;
+ d << index;
MOTH_END_INSTR(LoadQmlContextPropertyLookup)
MOTH_BEGIN_INSTR(StoreNameSloppy)
@@ -300,20 +269,19 @@ void dumpBytecode(const char *code, int len, int nLocals, int nFormals, int /*st
MOTH_END_INSTR(StoreNameStrict)
MOTH_BEGIN_INSTR(LoadElement)
- d << dumpRegister(base, nFormals) << "[acc]" << TRACE_SLOT;
+ d << dumpRegister(base, nFormals) << "[acc]";
MOTH_END_INSTR(LoadElement)
MOTH_BEGIN_INSTR(StoreElement)
- d << dumpRegister(base, nFormals) << "[" << dumpRegister(index, nFormals) << "]"
- << TRACE_SLOT;
+ d << dumpRegister(base, nFormals) << "[" << dumpRegister(index, nFormals) << "]";
MOTH_END_INSTR(StoreElement)
MOTH_BEGIN_INSTR(LoadProperty)
- d << "acc[" << name << "]" << TRACE_SLOT;
+ d << "acc[" << name << "]";
MOTH_END_INSTR(LoadProperty)
MOTH_BEGIN_INSTR(GetLookup)
- d << "acc(" << index << ")" << TRACE_SLOT;
+ d << "acc(" << index << ")";
MOTH_END_INSTR(GetLookup)
MOTH_BEGIN_INSTR(StoreProperty)
@@ -343,49 +311,48 @@ void dumpBytecode(const char *code, int len, int nLocals, int nFormals, int /*st
MOTH_END_INSTR(Resume)
MOTH_BEGIN_INSTR(CallValue)
- d << dumpRegister(name, nFormals) << dumpArguments(argc, argv, nFormals) << TRACE_SLOT;
+ d << dumpRegister(name, nFormals) << dumpArguments(argc, argv, nFormals);
MOTH_END_INSTR(CallValue)
MOTH_BEGIN_INSTR(CallWithReceiver)
d << dumpRegister(name, nFormals) << dumpRegister(thisObject, nFormals)
- << dumpArguments(argc, argv, nFormals) << TRACE_SLOT;
+ << dumpArguments(argc, argv, nFormals);
MOTH_END_INSTR(CallWithReceiver)
MOTH_BEGIN_INSTR(CallProperty)
d << dumpRegister(base, nFormals) << "." << name << dumpArguments(argc, argv, nFormals)
- << TRACE_SLOT;
+ ;
MOTH_END_INSTR(CallProperty)
MOTH_BEGIN_INSTR(CallPropertyLookup)
d << dumpRegister(base, nFormals) << "." << lookupIndex
- << dumpArguments(argc, argv, nFormals) << TRACE_SLOT;
+ << dumpArguments(argc, argv, nFormals);
MOTH_END_INSTR(CallPropertyLookup)
MOTH_BEGIN_INSTR(CallElement)
d << dumpRegister(base, nFormals) << "[" << dumpRegister(index, nFormals) << "]"
- << dumpArguments(argc, argv, nFormals) << TRACE_SLOT;
+ << dumpArguments(argc, argv, nFormals);
MOTH_END_INSTR(CallElement)
MOTH_BEGIN_INSTR(CallName)
- d << name << dumpArguments(argc, argv, nFormals) << TRACE_SLOT;
+ d << name << dumpArguments(argc, argv, nFormals);
MOTH_END_INSTR(CallName)
MOTH_BEGIN_INSTR(CallPossiblyDirectEval)
- d << dumpArguments(argc, argv, nFormals) << TRACE_SLOT;
+ d << dumpArguments(argc, argv, nFormals);
MOTH_END_INSTR(CallPossiblyDirectEval)
MOTH_BEGIN_INSTR(CallGlobalLookup)
- d << index << dumpArguments(argc, argv, nFormals) << TRACE_SLOT;
+ d << index << dumpArguments(argc, argv, nFormals);
MOTH_END_INSTR(CallGlobalLookup)
MOTH_BEGIN_INSTR(CallQmlContextPropertyLookup)
- d << index << dumpArguments(argc, argv, nFormals) << TRACE_SLOT;
+ d << index << dumpArguments(argc, argv, nFormals);
MOTH_END_INSTR(CallQmlContextPropertyLookup)
MOTH_BEGIN_INSTR(CallWithSpread)
d << "new " << dumpRegister(func, nFormals) << dumpRegister(thisObject, nFormals)
- << dumpArguments(argc, argv, nFormals)
- << TRACE_SLOT;
+ << dumpArguments(argc, argv, nFormals);
MOTH_END_INSTR(CallWithSpread)
MOTH_BEGIN_INSTR(Construct)
@@ -528,11 +495,11 @@ void dumpBytecode(const char *code, int len, int nLocals, int nFormals, int /*st
MOTH_END_INSTR(Jump)
MOTH_BEGIN_INSTR(JumpTrue)
- d << ABSOLUTE_OFFSET() << TRACE_SLOT;
+ d << ABSOLUTE_OFFSET();
MOTH_END_INSTR(JumpTrue)
MOTH_BEGIN_INSTR(JumpFalse)
- d << ABSOLUTE_OFFSET() << TRACE_SLOT;
+ d << ABSOLUTE_OFFSET();
MOTH_END_INSTR(JumpFalse)
MOTH_BEGIN_INSTR(JumpNotUndefined)
@@ -543,6 +510,9 @@ void dumpBytecode(const char *code, int len, int nLocals, int nFormals, int /*st
d << ABSOLUTE_OFFSET();
MOTH_END_INSTR(JumpNoException)
+ MOTH_BEGIN_INSTR(CheckException)
+ MOTH_END_INSTR(CheckException)
+
MOTH_BEGIN_INSTR(CmpEqNull)
MOTH_END_INSTR(CmpEqNull)
@@ -596,22 +566,19 @@ void dumpBytecode(const char *code, int len, int nLocals, int nFormals, int /*st
MOTH_END_INSTR(UPlus)
MOTH_BEGIN_INSTR(UMinus)
- d << TRACE_SLOT;
MOTH_END_INSTR(UMinus)
MOTH_BEGIN_INSTR(UCompl)
MOTH_END_INSTR(UCompl)
MOTH_BEGIN_INSTR(Increment)
- d << TRACE_SLOT;
MOTH_END_INSTR(Increment)
MOTH_BEGIN_INSTR(Decrement)
- d << TRACE_SLOT;
MOTH_END_INSTR(Decrement)
MOTH_BEGIN_INSTR(Add)
- d << dumpRegister(lhs, nFormals) << ", acc" << TRACE_SLOT;
+ d << dumpRegister(lhs, nFormals) << ", acc";
MOTH_END_INSTR(Add)
MOTH_BEGIN_INSTR(BitAnd)
@@ -667,7 +634,7 @@ void dumpBytecode(const char *code, int len, int nLocals, int nFormals, int /*st
MOTH_END_INSTR(Exp)
MOTH_BEGIN_INSTR(Mul)
- d << dumpRegister(lhs, nFormals) << ", acc" << TRACE_SLOT;
+ d << dumpRegister(lhs, nFormals) << ", acc";
MOTH_END_INSTR(Mul)
MOTH_BEGIN_INSTR(Div)
@@ -675,11 +642,11 @@ void dumpBytecode(const char *code, int len, int nLocals, int nFormals, int /*st
MOTH_END_INSTR(Div)
MOTH_BEGIN_INSTR(Mod)
- d << dumpRegister(lhs, nFormals) << ", acc" << TRACE_SLOT;
+ d << dumpRegister(lhs, nFormals) << ", acc";
MOTH_END_INSTR(Mod)
MOTH_BEGIN_INSTR(Sub)
- d << dumpRegister(lhs, nFormals) << ", acc" << TRACE_SLOT;
+ d << dumpRegister(lhs, nFormals) << ", acc";
MOTH_END_INSTR(Sub)
MOTH_BEGIN_INSTR(CmpIn)
diff --git a/src/qml/compiler/qv4instr_moth_p.h b/src/qml/compiler/qv4instr_moth_p.h
index 26901c297c..c0dd696b8a 100644
--- a/src/qml/compiler/qv4instr_moth_p.h
+++ b/src/qml/compiler/qv4instr_moth_p.h
@@ -50,9 +50,8 @@
//
// We mean it.
//
-#include <private/qv4global_p.h>
-#include <private/qv4value_p.h>
-#include <private/qv4runtime_p.h>
+
+#include <private/qv4staticvalue_p.h>
#include <private/qv4compileddata_p.h> // for CompiledData::CodeOffsetToLine used by the dumper
#include <qendian.h>
@@ -77,20 +76,20 @@ QT_BEGIN_NAMESPACE
#define INSTR_StoreReg(op) INSTRUCTION(op, StoreReg, 1, reg)
#define INSTR_MoveReg(op) INSTRUCTION(op, MoveReg, 2, srcReg, destReg)
#define INSTR_LoadImport(op) INSTRUCTION(op, LoadImport, 1, index)
-#define INSTR_LoadLocal(op) INSTRUCTION(op, LoadLocal, 2, index, traceSlot)
+#define INSTR_LoadLocal(op) INSTRUCTION(op, LoadLocal, 1, index)
#define INSTR_StoreLocal(op) INSTRUCTION(op, StoreLocal, 1, index)
-#define INSTR_LoadScopedLocal(op) INSTRUCTION(op, LoadScopedLocal, 3, scope, index, traceSlot)
+#define INSTR_LoadScopedLocal(op) INSTRUCTION(op, LoadScopedLocal, 2, scope, index)
#define INSTR_StoreScopedLocal(op) INSTRUCTION(op, StoreScopedLocal, 2, scope, index)
#define INSTR_LoadRuntimeString(op) INSTRUCTION(op, LoadRuntimeString, 1, stringId)
#define INSTR_MoveRegExp(op) INSTRUCTION(op, MoveRegExp, 2, regExpId, destReg)
#define INSTR_LoadClosure(op) INSTRUCTION(op, LoadClosure, 1, value)
-#define INSTR_LoadName(op) INSTRUCTION(op, LoadName, 2, name, traceSlot)
-#define INSTR_LoadGlobalLookup(op) INSTRUCTION(op, LoadGlobalLookup, 2, index, traceSlot)
-#define INSTR_LoadQmlContextPropertyLookup(op) INSTRUCTION(op, LoadQmlContextPropertyLookup, 2, index, traceSlot)
+#define INSTR_LoadName(op) INSTRUCTION(op, LoadName, 1, name)
+#define INSTR_LoadGlobalLookup(op) INSTRUCTION(op, LoadGlobalLookup, 1, index)
+#define INSTR_LoadQmlContextPropertyLookup(op) INSTRUCTION(op, LoadQmlContextPropertyLookup, 1, index)
#define INSTR_StoreNameSloppy(op) INSTRUCTION(op, StoreNameSloppy, 1, name)
#define INSTR_StoreNameStrict(op) INSTRUCTION(op, StoreNameStrict, 1, name)
-#define INSTR_LoadProperty(op) INSTRUCTION(op, LoadProperty, 2, name, traceSlot)
-#define INSTR_GetLookup(op) INSTRUCTION(op, GetLookup, 2, index, traceSlot)
+#define INSTR_LoadProperty(op) INSTRUCTION(op, LoadProperty, 1, name)
+#define INSTR_GetLookup(op) INSTRUCTION(op, GetLookup, 1, index)
#define INSTR_LoadIdObject(op) INSTRUCTION(op, LoadIdObject, 2, index, base)
#define INSTR_Yield(op) INSTRUCTION(op, Yield, 0)
#define INSTR_YieldStar(op) INSTRUCTION(op, YieldStar, 0)
@@ -100,18 +99,18 @@ QT_BEGIN_NAMESPACE
#define INSTR_SetLookup(op) INSTRUCTION(op, SetLookup, 2, index, base)
#define INSTR_LoadSuperProperty(op) INSTRUCTION(op, LoadSuperProperty, 1, property)
#define INSTR_StoreSuperProperty(op) INSTRUCTION(op, StoreSuperProperty, 1, property)
-#define INSTR_LoadElement(op) INSTRUCTION(op, LoadElement, 2, base, traceSlot)
-#define INSTR_StoreElement(op) INSTRUCTION(op, StoreElement, 3, base, index, traceSlot)
-#define INSTR_CallValue(op) INSTRUCTION(op, CallValue, 4, name, argc, argv, traceSlot)
-#define INSTR_CallWithReceiver(op) INSTRUCTION(op, CallWithReceiver, 5, name, thisObject, argc, argv, traceSlot)
-#define INSTR_CallProperty(op) INSTRUCTION(op, CallProperty, 5, name, base, argc, argv, traceSlot)
-#define INSTR_CallPropertyLookup(op) INSTRUCTION(op, CallPropertyLookup, 5, lookupIndex, base, argc, argv, traceSlot)
-#define INSTR_CallElement(op) INSTRUCTION(op, CallElement, 5, base, index, argc, argv, traceSlot)
-#define INSTR_CallName(op) INSTRUCTION(op, CallName, 4, name, argc, argv, traceSlot)
-#define INSTR_CallPossiblyDirectEval(op) INSTRUCTION(op, CallPossiblyDirectEval, 3, argc, argv, traceSlot)
-#define INSTR_CallGlobalLookup(op) INSTRUCTION(op, CallGlobalLookup, 4, index, argc, argv, traceSlot)
-#define INSTR_CallQmlContextPropertyLookup(op) INSTRUCTION(op, CallQmlContextPropertyLookup, 4, index, argc, argv, traceSlot)
-#define INSTR_CallWithSpread(op) INSTRUCTION(op, CallWithSpread, 5, func, thisObject, argc, argv, traceSlot)
+#define INSTR_LoadElement(op) INSTRUCTION(op, LoadElement, 1, base)
+#define INSTR_StoreElement(op) INSTRUCTION(op, StoreElement, 2, base, index)
+#define INSTR_CallValue(op) INSTRUCTION(op, CallValue, 3, name, argc, argv)
+#define INSTR_CallWithReceiver(op) INSTRUCTION(op, CallWithReceiver, 4, name, thisObject, argc, argv)
+#define INSTR_CallProperty(op) INSTRUCTION(op, CallProperty, 4, name, base, argc, argv)
+#define INSTR_CallPropertyLookup(op) INSTRUCTION(op, CallPropertyLookup, 4, lookupIndex, base, argc, argv)
+#define INSTR_CallElement(op) INSTRUCTION(op, CallElement, 4, base, index, argc, argv)
+#define INSTR_CallName(op) INSTRUCTION(op, CallName, 3, name, argc, argv)
+#define INSTR_CallPossiblyDirectEval(op) INSTRUCTION(op, CallPossiblyDirectEval, 2, argc, argv)
+#define INSTR_CallGlobalLookup(op) INSTRUCTION(op, CallGlobalLookup, 3, index, argc, argv)
+#define INSTR_CallQmlContextPropertyLookup(op) INSTRUCTION(op, CallQmlContextPropertyLookup, 3, index, argc, argv)
+#define INSTR_CallWithSpread(op) INSTRUCTION(op, CallWithSpread, 4, func, thisObject, argc, argv)
#define INSTR_Construct(op) INSTRUCTION(op, Construct, 3, func, argc, argv)
#define INSTR_ConstructWithSpread(op) INSTRUCTION(op, ConstructWithSpread, 3, func, argc, argv)
#define INSTR_SetUnwindHandler(op) INSTRUCTION(op, SetUnwindHandler, 1, offset)
@@ -148,10 +147,11 @@ QT_BEGIN_NAMESPACE
#define INSTR_LoadSuperConstructor(op) INSTRUCTION(op, LoadSuperConstructor, 0)
#define INSTR_ToObject(op) INSTRUCTION(op, ToObject, 0)
#define INSTR_Jump(op) INSTRUCTION(op, Jump, 1, offset)
-#define INSTR_JumpTrue(op) INSTRUCTION(op, JumpTrue, 2, traceSlot, offset)
-#define INSTR_JumpFalse(op) INSTRUCTION(op, JumpFalse, 2, traceSlot, offset)
+#define INSTR_JumpTrue(op) INSTRUCTION(op, JumpTrue, 1, offset)
+#define INSTR_JumpFalse(op) INSTRUCTION(op, JumpFalse, 1, offset)
#define INSTR_JumpNotUndefined(op) INSTRUCTION(op, JumpNotUndefined, 1, offset)
#define INSTR_JumpNoException(op) INSTRUCTION(op, JumpNoException, 1, offset)
+#define INSTR_CheckException(op) INSTRUCTION(op, CheckException, 0)
#define INSTR_CmpEqNull(op) INSTRUCTION(op, CmpEqNull, 0)
#define INSTR_CmpNeNull(op) INSTRUCTION(op, CmpNeNull, 0)
#define INSTR_CmpEqInt(op) INSTRUCTION(op, CmpEqInt, 1, lhs)
@@ -168,11 +168,11 @@ QT_BEGIN_NAMESPACE
#define INSTR_CmpInstanceOf(op) INSTRUCTION(op, CmpInstanceOf, 1, lhs)
#define INSTR_UNot(op) INSTRUCTION(op, UNot, 0)
#define INSTR_UPlus(op) INSTRUCTION(op, UPlus, 0)
-#define INSTR_UMinus(op) INSTRUCTION(op, UMinus, 1, traceSlot)
+#define INSTR_UMinus(op) INSTRUCTION(op, UMinus, 0)
#define INSTR_UCompl(op) INSTRUCTION(op, UCompl, 0)
-#define INSTR_Increment(op) INSTRUCTION(op, Increment, 1, traceSlot)
-#define INSTR_Decrement(op) INSTRUCTION(op, Decrement, 1, traceSlot)
-#define INSTR_Add(op) INSTRUCTION(op, Add, 2, lhs, traceSlot)
+#define INSTR_Increment(op) INSTRUCTION(op, Increment, 0)
+#define INSTR_Decrement(op) INSTRUCTION(op, Decrement, 0)
+#define INSTR_Add(op) INSTRUCTION(op, Add, 1, lhs)
#define INSTR_BitAnd(op) INSTRUCTION(op, BitAnd, 1, lhs)
#define INSTR_BitOr(op) INSTRUCTION(op, BitOr, 1, lhs)
#define INSTR_BitXor(op) INSTRUCTION(op, BitXor, 1, lhs)
@@ -186,10 +186,10 @@ QT_BEGIN_NAMESPACE
#define INSTR_ShrConst(op) INSTRUCTION(op, ShrConst, 1, rhs)
#define INSTR_ShlConst(op) INSTRUCTION(op, ShlConst, 1, rhs)
#define INSTR_Exp(op) INSTRUCTION(op, Exp, 1, lhs)
-#define INSTR_Mul(op) INSTRUCTION(op, Mul, 2, lhs, traceSlot)
+#define INSTR_Mul(op) INSTRUCTION(op, Mul, 1, lhs)
#define INSTR_Div(op) INSTRUCTION(op, Div, 1, lhs)
-#define INSTR_Mod(op) INSTRUCTION(op, Mod, 2, lhs, traceSlot)
-#define INSTR_Sub(op) INSTRUCTION(op, Sub, 2, lhs, traceSlot)
+#define INSTR_Mod(op) INSTRUCTION(op, Mod, 1, lhs)
+#define INSTR_Sub(op) INSTRUCTION(op, Sub, 1, lhs)
#define INSTR_LoadQmlImportedScripts(op) INSTRUCTION(op, LoadQmlImportedScripts, 1, result)
#define INSTR_InitializeBlockDeadTemporalZone(op) INSTRUCTION(op, InitializeBlockDeadTemporalZone, 2, firstReg, count)
#define INSTR_ThrowOnNullOrUndefined(op) INSTRUCTION(op, ThrowOnNullOrUndefined, 0)
@@ -241,6 +241,7 @@ QT_BEGIN_NAMESPACE
F(JumpFalse) \
F(JumpNoException) \
F(JumpNotUndefined) \
+ F(CheckException) \
F(CmpEqNull) \
F(CmpNeNull) \
F(CmpEqInt) \
@@ -532,7 +533,6 @@ inline bool operator!=(const StackSlot &l, const StackSlot &r) { return l.stackS
// When making changes to the instructions, make sure to bump QV4_DATA_STRUCTURE_VERSION in qv4compileddata_p.h
-void dumpConstantTable(const Value *constants, uint count);
void dumpBytecode(const char *bytecode, int len, int nLocals, int nFormals, int startLine = 1,
const QVector<CompiledData::CodeOffsetToLine> &lineNumberMapping = QVector<CompiledData::CodeOffsetToLine>());
inline void dumpBytecode(const QByteArray &bytecode, int nLocals, int nFormals, int startLine = 1,
diff --git a/src/qml/compiler/qv4util_p.h b/src/qml/compiler/qv4util_p.h
new file mode 100644
index 0000000000..bd9758c1fb
--- /dev/null
+++ b/src/qml/compiler/qv4util_p.h
@@ -0,0 +1,195 @@
+/****************************************************************************
+**
+** 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 QV4UTIL_H
+#define QV4UTIL_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/QBitArray>
+#include <algorithm>
+#include <vector>
+
+QT_BEGIN_NAMESPACE
+
+namespace QV4 {
+
+#if !defined(BROKEN_STD_VECTOR_BOOL_OR_BROKEN_STD_FIND)
+// Sanity:
+class BitVector
+{
+ std::vector<bool> bits;
+
+public:
+ BitVector(int size = 0, bool value = false)
+ : bits(size, value)
+ {}
+
+ void clear()
+ { bits = std::vector<bool>(bits.size(), false); }
+
+ void reserve(int size)
+ { bits.reserve(size); }
+
+ int size() const
+ {
+ Q_ASSERT(bits.size() < INT_MAX);
+ return static_cast<int>(bits.size());
+ }
+
+ void resize(int newSize)
+ { bits.resize(newSize); }
+
+ void resize(int newSize, bool newValue)
+ { bits.resize(newSize, newValue); }
+
+ void assign(int newSize, bool value)
+ { bits.assign(newSize, value); }
+
+ int findNext(int start, bool value, bool wrapAround) const
+ {
+ // The ++operator of std::vector<bool>::iterator in libc++ has a bug when using it on an
+ // iterator pointing to the last element. It will not be set to ::end(), but beyond
+ // that. (It will be set to the first multiple of the native word size that is bigger
+ // than size().)
+ //
+ // See http://llvm.org/bugs/show_bug.cgi?id=19663
+ //
+ // The work-around is to calculate the distance, and compare it to the size() to see if it's
+ // beyond the end, or take the minimum of the distance and the size.
+
+ size_t pos = std::distance(bits.begin(),
+ std::find(bits.begin() + start, bits.end(), value));
+ if (wrapAround && pos >= static_cast<size_t>(size()))
+ pos = std::distance(bits.begin(),
+ std::find(bits.begin(), bits.begin() + start, value));
+
+ pos = qMin(pos, static_cast<size_t>(size()));
+
+ Q_ASSERT(pos <= static_cast<size_t>(size()));
+ Q_ASSERT(pos < INT_MAX);
+
+ return static_cast<int>(pos);
+ }
+
+ bool at(int idx) const
+ { return bits.at(idx); }
+
+ void setBit(int idx)
+ { bits[idx] = true; }
+
+ void clearBit(int idx)
+ { bits[idx] = false; }
+};
+#else // Insanity:
+class BitVector
+{
+ QBitArray bits;
+
+public:
+ BitVector(int size = 0, bool value = false)
+ : bits(size, value)
+ {}
+
+ void clear()
+ { bits = QBitArray(bits.size(), false); }
+
+ void reserve(int size)
+ { Q_UNUSED(size); }
+
+ int size() const
+ { return bits.size(); }
+
+ void resize(int newSize)
+ { bits.resize(newSize); }
+
+ void resize(int newSize, bool newValue)
+ {
+ int oldSize = bits.size();
+ bits.resize(newSize);
+ bits.fill(newValue, oldSize, bits.size());
+ }
+
+ void assign(int newSize, bool value)
+ {
+ bits.resize(newSize);
+ bits.fill(value);
+ }
+
+ int findNext(int start, bool value, bool wrapAround) const
+ {
+ for (int i = start, ei = size(); i < ei; ++i) {
+ if (at(i) == value)
+ return i;
+ }
+
+ if (wrapAround) {
+ for (int i = 0, ei = start; i < ei; ++i) {
+ if (at(i) == value)
+ return i;
+ }
+ }
+
+ return size();
+ }
+
+ bool at(int idx) const
+ { return bits.at(idx); }
+
+ void setBit(int idx)
+ { bits[idx] = true; }
+
+ void clearBit(int idx)
+ { bits[idx] = false; }
+};
+#endif
+
+}
+
+QT_END_NAMESPACE
+
+#endif // QV4UTIL_H