diff options
Diffstat (limited to 'src/qml/compiler/qqmlirbuilder.cpp')
-rw-r--r-- | src/qml/compiler/qqmlirbuilder.cpp | 582 |
1 files changed, 175 insertions, 407 deletions
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 ¶meterName, + 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(¶m->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 |