diff options
Diffstat (limited to 'src/qml/compiler')
-rw-r--r-- | src/qml/compiler/qqmlirbuilder.cpp | 37 | ||||
-rw-r--r-- | src/qml/compiler/qqmlirbuilder_p.h | 16 | ||||
-rw-r--r-- | src/qml/compiler/qqmltypecompiler.cpp | 154 | ||||
-rw-r--r-- | src/qml/compiler/qqmltypecompiler_p.h | 20 | ||||
-rw-r--r-- | src/qml/compiler/qv4codegen.cpp | 3 | ||||
-rw-r--r-- | src/qml/compiler/qv4codegen_p.h | 11 | ||||
-rw-r--r-- | src/qml/compiler/qv4compileddata.cpp | 2 | ||||
-rw-r--r-- | src/qml/compiler/qv4compileddata_p.h | 11 | ||||
-rw-r--r-- | src/qml/compiler/qv4compiler.cpp | 7 | ||||
-rw-r--r-- | src/qml/compiler/qv4compiler_p.h | 11 | ||||
-rw-r--r-- | src/qml/compiler/qv4instr_moth_p.h | 105 | ||||
-rw-r--r-- | src/qml/compiler/qv4isel_moth.cpp | 110 | ||||
-rw-r--r-- | src/qml/compiler/qv4isel_moth_p.h | 19 | ||||
-rw-r--r-- | src/qml/compiler/qv4isel_p.cpp | 55 | ||||
-rw-r--r-- | src/qml/compiler/qv4isel_p.h | 19 | ||||
-rw-r--r-- | src/qml/compiler/qv4isel_util_p.h | 11 | ||||
-rw-r--r-- | src/qml/compiler/qv4jsir.cpp | 24 | ||||
-rw-r--r-- | src/qml/compiler/qv4jsir_p.h | 65 | ||||
-rw-r--r-- | src/qml/compiler/qv4ssa.cpp | 165 | ||||
-rw-r--r-- | src/qml/compiler/qv4ssa_p.h | 11 |
20 files changed, 605 insertions, 251 deletions
diff --git a/src/qml/compiler/qqmlirbuilder.cpp b/src/qml/compiler/qqmlirbuilder.cpp index 63833504f1..16c4cb28ed 100644 --- a/src/qml/compiler/qqmlirbuilder.cpp +++ b/src/qml/compiler/qqmlirbuilder.cpp @@ -33,7 +33,7 @@ #include "qqmlirbuilder_p.h" -#include <private/qv4value_inl_p.h> +#include <private/qv4value_p.h> #include <private/qv4compileddata_p.h> #include <private/qqmljsparser_p.h> #include <private/qqmljslexer_p.h> @@ -1456,10 +1456,8 @@ JSCodeGen::JSCodeGen(const QString &fileName, const QString &sourceCode, QV4::IR , _disableAcceleratedLookups(false) , _contextObject(0) , _scopeObject(0) - , _contextObjectTemp(-1) - , _scopeObjectTemp(-1) + , _qmlContextTemp(-1) , _importedScriptsTemp(-1) - , _idArrayTemp(-1) { _module = jsModule; _module->setFileName(fileName); @@ -1592,7 +1590,7 @@ static QV4::IR::Type resolveQmlType(QQmlEnginePrivate *qmlEngine, QV4::IR::Membe if (member->name->constData()->isUpper()) { bool ok = false; - int value = type->enumValue(*member->name, &ok); + int value = type->enumValue(qmlEngine, *member->name, &ok); if (ok) { member->setEnumValue(value); resolver->clear(); @@ -1617,10 +1615,10 @@ static QV4::IR::Type resolveQmlType(QQmlEnginePrivate *qmlEngine, QV4::IR::Membe member->kind = QV4::IR::Member::MemberOfSingletonObject; return resolver->resolveMember(qmlEngine, resolver, member); } - } else if (const QMetaObject *attachedMeta = type->attachedPropertiesType()) { + } else if (const QMetaObject *attachedMeta = type->attachedPropertiesType(qmlEngine)) { QQmlPropertyCache *cache = qmlEngine->cache(attachedMeta); initMetaObjectResolver(resolver, cache); - member->setAttachedPropertiesId(type->attachedPropertiesId()); + member->setAttachedPropertiesId(type->attachedPropertiesId(qmlEngine)); return resolver->resolveMember(qmlEngine, resolver, member); } @@ -1695,7 +1693,8 @@ static QV4::IR::Type resolveMetaObjectProperty(QQmlEnginePrivate *qmlEngine, QV4 } } - if (qmlEngine && !(resolver->flags & LookupsExcludeProperties)) { + if (member->kind != QV4::IR::Member::MemberOfIdObjectsArray && member->kind != QV4::IR::Member::MemberOfSingletonObject && + qmlEngine && !(resolver->flags & LookupsExcludeProperties)) { QQmlPropertyData *property = member->property; if (!property && metaObject) { if (QQmlPropertyData *candidate = metaObject->property(*member->name, /*object*/0, /*context*/0)) { @@ -1764,24 +1763,14 @@ static void initMetaObjectResolver(QV4::IR::MemberExpressionResolver *resolver, void JSCodeGen::beginFunctionBodyHook() { - _contextObjectTemp = _block->newTemp(); - _scopeObjectTemp = _block->newTemp(); + _qmlContextTemp = _block->newTemp(); _importedScriptsTemp = _block->newTemp(); - _idArrayTemp = _block->newTemp(); #ifndef V4_BOOTSTRAP - QV4::IR::Temp *temp = _block->TEMP(_contextObjectTemp); - temp->memberResolver = _function->New<QV4::IR::MemberExpressionResolver>(); - initMetaObjectResolver(temp->memberResolver, _contextObject); - move(temp, _block->NAME(QV4::IR::Name::builtin_qml_context_object, 0, 0)); - - temp = _block->TEMP(_scopeObjectTemp); - temp->memberResolver = _function->New<QV4::IR::MemberExpressionResolver>(); - initMetaObjectResolver(temp->memberResolver, _scopeObject); - move(temp, _block->NAME(QV4::IR::Name::builtin_qml_scope_object, 0, 0)); + QV4::IR::Temp *temp = _block->TEMP(_qmlContextTemp); + move(temp, _block->NAME(QV4::IR::Name::builtin_qml_context, 0, 0)); move(_block->TEMP(_importedScriptsTemp), _block->NAME(QV4::IR::Name::builtin_qml_imported_scripts_object, 0, 0)); - move(_block->TEMP(_idArrayTemp), _block->NAME(QV4::IR::Name::builtin_qml_id_array, 0, 0)); #endif } @@ -1807,7 +1796,7 @@ QV4::IR::Expr *JSCodeGen::fallbackNameLookup(const QString &name, int line, int foreach (const IdMapping &mapping, _idObjects) if (name == mapping.name) { _function->idObjectDependencies.insert(mapping.idIndex); - QV4::IR::Expr *s = subscript(_block->TEMP(_idArrayTemp), _block->CONST(QV4::IR::SInt32Type, mapping.idIndex)); + QV4::IR::Expr *s = _block->MEMBER(_block->TEMP(_qmlContextTemp), _function->newString(name), 0, QV4::IR::Member::MemberOfIdObjectsArray, mapping.idIndex); QV4::IR::Temp *result = _block->TEMP(_block->newTemp()); _block->MOVE(result, s); result = _block->TEMP(result->index); @@ -1857,7 +1846,7 @@ QV4::IR::Expr *JSCodeGen::fallbackNameLookup(const QString &name, int line, int if (propertyExistsButForceNameLookup) return 0; if (pd) { - QV4::IR::Temp *base = _block->TEMP(_scopeObjectTemp); + QV4::IR::Temp *base = _block->TEMP(_qmlContextTemp); base->memberResolver = _function->New<QV4::IR::MemberExpressionResolver>(); initMetaObjectResolver(base->memberResolver, _scopeObject); return _block->MEMBER(base, _function->newString(name), pd, QV4::IR::Member::MemberOfQmlScopeObject); @@ -1870,7 +1859,7 @@ QV4::IR::Expr *JSCodeGen::fallbackNameLookup(const QString &name, int line, int if (propertyExistsButForceNameLookup) return 0; if (pd) { - QV4::IR::Temp *base = _block->TEMP(_contextObjectTemp); + QV4::IR::Temp *base = _block->TEMP(_qmlContextTemp); base->memberResolver = _function->New<QV4::IR::MemberExpressionResolver>(); initMetaObjectResolver(base->memberResolver, _contextObject); return _block->MEMBER(base, _function->newString(name), pd, QV4::IR::Member::MemberOfQmlContextObject); diff --git a/src/qml/compiler/qqmlirbuilder_p.h b/src/qml/compiler/qqmlirbuilder_p.h index 120de91321..9a659f4d72 100644 --- a/src/qml/compiler/qqmlirbuilder_p.h +++ b/src/qml/compiler/qqmlirbuilder_p.h @@ -33,8 +33,18 @@ #ifndef QQMLIRBUILDER_P_H #define QQMLIRBUILDER_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/qqmljsast_p.h> -#include <private/qqmlpool_p.h> #include <private/qqmljsengine_p.h> #include <private/qv4compiler_p.h> #include <private/qv4compileddata_p.h> @@ -496,10 +506,8 @@ private: ObjectIdMapping _idObjects; QQmlPropertyCache *_contextObject; QQmlPropertyCache *_scopeObject; - int _contextObjectTemp; - int _scopeObjectTemp; + int _qmlContextTemp; int _importedScriptsTemp; - int _idArrayTemp; }; } // namespace QmlIR diff --git a/src/qml/compiler/qqmltypecompiler.cpp b/src/qml/compiler/qqmltypecompiler.cpp index 4e9817aa0d..cde7a2acb4 100644 --- a/src/qml/compiler/qqmltypecompiler.cpp +++ b/src/qml/compiler/qqmltypecompiler.cpp @@ -104,11 +104,10 @@ bool QQmlTypeCompiler::compile() } if (ref->type->containsRevisionedAttributes()) { - QQmlError cacheError; ref->typePropertyCache = engine->cache(ref->type, - resolvedType->minorVersion, - cacheError); + resolvedType->minorVersion); if (!ref->typePropertyCache) { + QQmlError cacheError; cacheError.setColumn(resolvedType->location.column); cacheError.setLine(resolvedType->location.line); recordError(cacheError); @@ -521,7 +520,24 @@ bool QQmlPropertyCacheCreator::buildMetaObjectRecursively(int objectIndex, int r } else if (instantiatingBinding && instantiatingBinding->isAttachedProperty()) { QQmlCompiledData::TypeReference *typeRef = resolvedTypes->value(instantiatingBinding->propertyNameIndex); Q_ASSERT(typeRef); - const QMetaObject *attachedMo = typeRef->type ? typeRef->type->attachedPropertiesType() : 0; + QQmlType *qmltype = typeRef->type; + if (!qmltype) { + QString propertyName = stringAt(instantiatingBinding->propertyNameIndex); + if (imports->resolveType(propertyName, &qmltype, 0, 0, 0)) { + if (qmltype->isComposite()) { + QQmlTypeData *tdata = enginePrivate->typeLoader.getType(qmltype->sourceUrl()); + Q_ASSERT(tdata); + Q_ASSERT(tdata->isComplete()); + + QQmlCompiledData *data = tdata->compiledData(); + qmltype = QQmlMetaType::qmlType(data->metaTypeId); + + tdata->release(); + } + } + } + + const QMetaObject *attachedMo = qmltype ? qmltype->attachedPropertiesType(enginePrivate) : 0; if (!attachedMo) { recordError(instantiatingBinding->location, tr("Non-existent attached object")); return false; @@ -668,17 +684,14 @@ bool QQmlPropertyCacheCreator::createMetaObject(int objectIndex, const QmlIR::Ob } // First set up notify signals for properties - first normal, then var, then alias - enum { NSS_Normal = 0, NSS_Var = 1, NSS_Alias = 2 }; + enum { NSS_Normal = 0, NSS_Alias = 1 }; for (int ii = NSS_Normal; ii <= NSS_Alias; ++ii) { // 0 == normal, 1 == var, 2 == alias - if (ii == NSS_Var && varPropCount == 0) continue; - else if (ii == NSS_Alias && aliasCount == 0) continue; + if (ii == NSS_Alias && aliasCount == 0) continue; for (const QmlIR::Property *p = obj->firstProperty(); p; p = p->next) { - if ((ii == NSS_Normal && (p->type == QV4::CompiledData::Property::Alias || - p->type == QV4::CompiledData::Property::Var)) || - ((ii == NSS_Var) && (p->type != QV4::CompiledData::Property::Var)) || - ((ii == NSS_Alias) && (p->type != QV4::CompiledData::Property::Alias))) + if ((ii == NSS_Normal && p->type == QV4::CompiledData::Property::Alias) || + (ii == NSS_Alias && p->type != QV4::CompiledData::Property::Alias)) continue; quint32 flags = QQmlPropertyData::IsSignal | QQmlPropertyData::IsFunction | @@ -696,6 +709,7 @@ bool QQmlPropertyCacheCreator::createMetaObject(int objectIndex, const QmlIR::Ob const int paramCount = s->parameters->count; QList<QByteArray> names; + names.reserve(paramCount); QVarLengthArray<int, 10> paramTypes(paramCount?(paramCount + 1):0); if (paramCount) { @@ -780,15 +794,18 @@ bool QQmlPropertyCacheCreator::createMetaObject(int objectIndex, const QmlIR::Ob int propertyIdx = 0; for (const QmlIR::Property *p = obj->firstProperty(); p; p = p->next, ++propertyIdx) { - if (p->type == QV4::CompiledData::Property::Alias || - p->type == QV4::CompiledData::Property::Var) + if (p->type == QV4::CompiledData::Property::Alias) continue; int propertyType = 0; int vmePropertyType = 0; quint32 propertyFlags = 0; - if (p->type < builtinTypeCount) { + if (p->type == QV4::CompiledData::Property::Var) { + propertyType = QMetaType::QVariant; + vmePropertyType = QQmlVMEMetaData::VarPropertyType; + propertyFlags = QQmlPropertyData::IsVarProperty; + } else if (p->type < builtinTypeCount) { propertyType = builtinTypes[p->type].metaType; vmePropertyType = propertyType; @@ -852,30 +869,6 @@ bool QQmlPropertyCacheCreator::createMetaObject(int objectIndex, const QmlIR::Ob vmd->propertyCount++; } - // Now do var properties - propertyIdx = 0; - for (const QmlIR::Property *p = obj->firstProperty(); p; p = p->next, ++propertyIdx) { - - if (p->type != QV4::CompiledData::Property::Var) - continue; - - quint32 propertyFlags = QQmlPropertyData::IsVarProperty; - if (!(p->flags & QV4::CompiledData::Property::IsReadOnly)) - propertyFlags |= QQmlPropertyData::IsWritable; - - VMD *vmd = (QQmlVMEMetaData *)dynamicData.data(); - (vmd->propertyData() + vmd->propertyCount)->propertyType = QMetaType::QVariant; - vmd->propertyCount++; - ((QQmlVMEMetaData *)dynamicData.data())->varPropertyCount++; - - QString propertyName = stringAt(p->nameIndex); - if (propertyIdx == obj->indexOfDefaultProperty) cache->_defaultPropertyName = propertyName; - cache->appendProperty(propertyName, propertyFlags, effectivePropertyIndex++, - QMetaType::QVariant, effectiveSignalIndex); - - effectiveSignalIndex++; - } - // Alias property count. Actual data is setup in buildDynamicMetaAliases ((QQmlVMEMetaData *)dynamicData.data())->aliasCount = aliasCount; @@ -904,7 +897,9 @@ bool QQmlPropertyCacheCreator::createMetaObject(int objectIndex, const QmlIR::Ob SignalHandlerConverter::SignalHandlerConverter(QQmlTypeCompiler *typeCompiler) : QQmlCompilePass(typeCompiler) + , enginePrivate(typeCompiler->enginePrivate()) , qmlObjects(*typeCompiler->qmlObjects()) + , imports(typeCompiler->imports()) , customParsers(typeCompiler->customParserCache()) , resolvedTypes(*typeCompiler->resolvedTypes()) , illegalNames(QV8Engine::get(QQmlEnginePrivate::get(typeCompiler->enginePrivate()))->illegalNames()) @@ -942,7 +937,22 @@ bool SignalHandlerConverter::convertSignalHandlerExpressionsToFunctionDeclaratio const QmlIR::Object *attachedObj = qmlObjects.at(binding->value.objectIndex); QQmlCompiledData::TypeReference *typeRef = resolvedTypes.value(binding->propertyNameIndex); QQmlType *type = typeRef ? typeRef->type : 0; - const QMetaObject *attachedType = type ? type->attachedPropertiesType() : 0; + if (!type) { + if (imports->resolveType(propertyName, &type, 0, 0, 0)) { + if (type->isComposite()) { + QQmlTypeData *tdata = enginePrivate->typeLoader.getType(type->sourceUrl()); + Q_ASSERT(tdata); + Q_ASSERT(tdata->isComplete()); + + QQmlCompiledData *data = tdata->compiledData(); + type = QQmlMetaType::qmlType(data->metaTypeId); + + tdata->release(); + } + } + } + + const QMetaObject *attachedType = type ? type->attachedPropertiesType(enginePrivate) : 0; if (!attachedType) COMPILE_EXCEPTION(binding, tr("Non-existent attached object")); QQmlPropertyCache *cache = compiler->enginePrivate()->cache(attachedType); @@ -1022,10 +1032,10 @@ bool SignalHandlerConverter::convertSignalHandlerExpressionsToFunctionDeclaratio } } - QHash<QString, QStringList>::ConstIterator entry = customSignals.find(propertyName); + QHash<QString, QStringList>::ConstIterator entry = customSignals.constFind(propertyName); if (entry == customSignals.constEnd() && propertyName.endsWith(QStringLiteral("Changed"))) { QString alternateName = propertyName.mid(0, propertyName.length() - static_cast<int>(strlen("Changed"))); - entry = customSignals.find(alternateName); + entry = customSignals.constFind(alternateName); } if (entry == customSignals.constEnd()) { @@ -1067,16 +1077,29 @@ bool SignalHandlerConverter::convertSignalHandlerExpressionsToFunctionDeclaratio paramList = paramList->finish(); QmlIR::CompiledFunctionOrExpression *foe = obj->functionsAndExpressions->slowAt(binding->value.compiledScriptIndex); - QQmlJS::AST::Statement *statement = static_cast<QQmlJS::AST::Statement*>(foe->node); - QQmlJS::AST::SourceElement *sourceElement = new (pool) QQmlJS::AST::StatementSourceElement(statement); - QQmlJS::AST::SourceElements *elements = new (pool) QQmlJS::AST::SourceElements(sourceElement); - elements = elements->finish(); - - QQmlJS::AST::FunctionBody *body = new (pool) QQmlJS::AST::FunctionBody(elements); + QQmlJS::AST::FunctionDeclaration *functionDeclaration = 0; + 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::SourceElement *sourceElement = new (pool) QQmlJS::AST::StatementSourceElement(statement); + QQmlJS::AST::SourceElements *elements = new (pool) QQmlJS::AST::SourceElements(sourceElement); + elements = elements->finish(); - QQmlJS::AST::FunctionDeclaration *functionDeclaration = new (pool) QQmlJS::AST::FunctionDeclaration(compiler->newStringRef(stringAt(binding->propertyNameIndex)), paramList, body); - functionDeclaration->functionToken = foe->node->firstSourceLocation(); + QQmlJS::AST::FunctionBody *body = new (pool) QQmlJS::AST::FunctionBody(elements); + functionDeclaration = new (pool) QQmlJS::AST::FunctionDeclaration(compiler->newStringRef(stringAt(binding->propertyNameIndex)), paramList, body); + functionDeclaration->functionToken = foe->node->firstSourceLocation(); + } foe->node = functionDeclaration; binding->propertyNameIndex = compiler->registerString(propertyName); binding->flags |= QV4::CompiledData::Binding::IsSignalHandlerExpression; @@ -1174,8 +1197,6 @@ bool QQmlEnumTypeResolver::tryQualifiedEnumAssignment(const QmlIR::Object *obj, if (!type && typeName != QLatin1String("Qt")) return true; - if (type && type->isComposite()) //No enums on composite (or composite singleton) types - return true; int value = 0; bool ok = false; @@ -1193,7 +1214,7 @@ bool QQmlEnumTypeResolver::tryQualifiedEnumAssignment(const QmlIR::Object *obj, } else { // Otherwise we have to search the whole type if (type) { - value = type->enumValue(QHashedStringRef(enumValue), &ok); + value = type->enumValue(compiler->enginePrivate(), QHashedStringRef(enumValue), &ok); } else { QByteArray enumName = enumValue.toUtf8(); const QMetaObject *metaObject = StaticQtMetaObject::get(); @@ -1221,7 +1242,9 @@ int QQmlEnumTypeResolver::evaluateEnum(const QString &scope, const QByteArray &e if (scope != QLatin1String("Qt")) { QQmlType *type = 0; imports->resolveType(scope, &type, 0, 0, 0); - return type ? type->enumValue(QHashedCStringRef(enumValue.constData(), enumValue.length()), ok) : -1; + if (!type) + return -1; + return type ? type->enumValue(compiler->enginePrivate(), QHashedCStringRef(enumValue.constData(), enumValue.length()), ok) : -1; } const QMetaObject *mo = StaticQtMetaObject::get(); @@ -1730,17 +1753,6 @@ const QQmlImports &QQmlPropertyValidator::imports() const return *compiler->imports(); } -QString QQmlPropertyValidator::bindingAsString(int objectIndex, const QV4::CompiledData::Binding *binding) const -{ - const QmlIR::Object *object = compiler->qmlObjects()->value(objectIndex); - if (!object) - return QString(); - int reverseIndex = object->runtimeFunctionIndices->indexOf(binding->value.compiledScriptIndex); - if (reverseIndex == -1) - return QString(); - return compiler->bindingAsString(object, reverseIndex); -} - typedef QVarLengthArray<const QV4::CompiledData::Binding *, 8> GroupPropertyVector; struct BindingFinder @@ -2009,15 +2021,17 @@ bool QQmlPropertyValidator::validateObject(int objectIndex, const QV4::CompiledD if (customParser && !customBindings.isEmpty()) { customParser->clearErrors(); - customParser->compiler = this; + customParser->validator = this; + customParser->engine = enginePrivate; customParser->imports = compiler->imports(); customParser->verifyBindings(qmlUnit, customBindings); - customParser->compiler = 0; + customParser->validator = 0; + customParser->engine = 0; customParser->imports = (QQmlImports*)0; customParserBindingsPerObject->insert(objectIndex, customParserBindings); const QList<QQmlError> parserErrors = customParser->errors(); if (!parserErrors.isEmpty()) { - foreach (QQmlError error, parserErrors) + foreach (const QQmlError &error, parserErrors) compiler->recordError(error); return false; } @@ -2623,10 +2637,8 @@ void QQmlJavaScriptBindingExpressionSimplificationPass::visitMove(QV4::IR::Move } if (QV4::IR::Name *n = move->source->asName()) { - if (n->builtin == QV4::IR::Name::builtin_qml_id_array - || n->builtin == QV4::IR::Name::builtin_qml_imported_scripts_object - || n->builtin == QV4::IR::Name::builtin_qml_context_object - || n->builtin == QV4::IR::Name::builtin_qml_scope_object) { + if (n->builtin == QV4::IR::Name::builtin_qml_context + || n->builtin == QV4::IR::Name::builtin_qml_imported_scripts_object) { // these are free of side-effects return; } diff --git a/src/qml/compiler/qqmltypecompiler_p.h b/src/qml/compiler/qqmltypecompiler_p.h index 75987af656..c5be92d256 100644 --- a/src/qml/compiler/qqmltypecompiler_p.h +++ b/src/qml/compiler/qqmltypecompiler_p.h @@ -33,6 +33,17 @@ #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> @@ -158,7 +169,9 @@ public: private: bool convertSignalHandlerExpressionsToFunctionDeclarations(const QmlIR::Object *obj, const QString &typeName, QQmlPropertyCache *propertyCache); + QQmlEnginePrivate *enginePrivate; const QList<QmlIR::Object*> &qmlObjects; + const QQmlImports *imports; const QHash<int, QQmlCustomParser*> &customParsers; const QHash<int, QQmlCompiledData::TypeReference*> &resolvedTypes; const QSet<QString> &illegalNames; @@ -264,7 +277,7 @@ protected: QHash<int, QHash<int, int> > *objectIndexToIdPerComponent; }; -class QQmlPropertyValidator : public QQmlCompilePass, public QQmlCustomParserCompilerBackend +class QQmlPropertyValidator : public QQmlCompilePass { Q_DECLARE_TR_FUNCTIONS(QQmlPropertyValidator) public: @@ -272,9 +285,8 @@ public: bool validate(); - // Re-implemented for QQmlCustomParser - virtual const QQmlImports &imports() const; - virtual QString bindingAsString(int objectIndex, const QV4::CompiledData::Binding *binding) const; + const QQmlImports &imports() const; + QQmlEnginePrivate *engine() const { return enginePrivate; } private: bool validateObject(int objectIndex, const QV4::CompiledData::Binding *instantiatingBinding, bool populatingValueTypeGroupProperty = false) const; diff --git a/src/qml/compiler/qv4codegen.cpp b/src/qml/compiler/qv4codegen.cpp index 9168889c8c..ea82d07e69 100644 --- a/src/qml/compiler/qv4codegen.cpp +++ b/src/qml/compiler/qv4codegen.cpp @@ -33,6 +33,7 @@ #include "qv4codegen_p.h" #include "qv4util_p.h" +#include "qv4engine_p.h" #include <QtCore/QCoreApplication> #include <QtCore/QStringList> @@ -43,7 +44,7 @@ #include <QtCore/QStack> #include <private/qqmljsast_p.h> #include <private/qv4string_p.h> -#include <private/qv4value_inl_p.h> +#include <private/qv4value_p.h> #ifndef V4_BOOTSTRAP #include <qv4context_p.h> diff --git a/src/qml/compiler/qv4codegen_p.h b/src/qml/compiler/qv4codegen_p.h index aec51cc19c..a7b0b06fe2 100644 --- a/src/qml/compiler/qv4codegen_p.h +++ b/src/qml/compiler/qv4codegen_p.h @@ -33,6 +33,17 @@ #ifndef QV4CODEGEN_P_H #define QV4CODEGEN_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/qv4global_p.h" #include "qv4jsir_p.h" #include <private/qqmljsastvisitor_p.h> diff --git a/src/qml/compiler/qv4compileddata.cpp b/src/qml/compiler/qv4compileddata.cpp index 5d954eb4fc..20db5edaa3 100644 --- a/src/qml/compiler/qv4compileddata.cpp +++ b/src/qml/compiler/qv4compileddata.cpp @@ -33,7 +33,7 @@ #include "qv4compileddata_p.h" #include "qv4jsir_p.h" -#include <private/qv4value_inl_p.h> +#include <private/qv4value_p.h> #ifndef V4_BOOTSTRAP #include <private/qv4engine_p.h> #include <private/qv4function_p.h> diff --git a/src/qml/compiler/qv4compileddata_p.h b/src/qml/compiler/qv4compileddata_p.h index 48324fbbc4..0d6e4b15a7 100644 --- a/src/qml/compiler/qv4compileddata_p.h +++ b/src/qml/compiler/qv4compileddata_p.h @@ -33,6 +33,17 @@ #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> diff --git a/src/qml/compiler/qv4compiler.cpp b/src/qml/compiler/qv4compiler.cpp index 450889c275..ba4bde7a31 100644 --- a/src/qml/compiler/qv4compiler.cpp +++ b/src/qml/compiler/qv4compiler.cpp @@ -35,7 +35,7 @@ #include <qv4compileddata_p.h> #include <qv4isel_p.h> #include <private/qv4string_p.h> -#include <private/qv4value_inl_p.h> +#include <private/qv4value_p.h> QV4::Compiler::StringTableGenerator::StringTableGenerator() { @@ -44,8 +44,8 @@ QV4::Compiler::StringTableGenerator::StringTableGenerator() int QV4::Compiler::StringTableGenerator::registerString(const QString &str) { - QHash<QString, int>::ConstIterator it = stringToId.find(str); - if (it != stringToId.end()) + QHash<QString, int>::ConstIterator it = stringToId.constFind(str); + if (it != stringToId.cend()) return *it; stringToId.insert(str, strings.size()); strings.append(str); @@ -169,6 +169,7 @@ int QV4::Compiler::JSUnitGenerator::registerJSClass(int count, IR::ExprList *arg // ### re-use existing class definitions. QList<CompiledData::JSClassMember> members; + members.reserve(count); IR::ExprList *it = args; for (int i = 0; i < count; ++i, it = it->next) { diff --git a/src/qml/compiler/qv4compiler_p.h b/src/qml/compiler/qv4compiler_p.h index 3cf80a9791..d999a93f4f 100644 --- a/src/qml/compiler/qv4compiler_p.h +++ b/src/qml/compiler/qv4compiler_p.h @@ -33,6 +33,17 @@ #ifndef QV4COMPILER_P_H #define QV4COMPILER_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 "qv4jsir_p.h" diff --git a/src/qml/compiler/qv4instr_moth_p.h b/src/qml/compiler/qv4instr_moth_p.h index 5c2ad45da2..97aee80e91 100644 --- a/src/qml/compiler/qv4instr_moth_p.h +++ b/src/qml/compiler/qv4instr_moth_p.h @@ -34,6 +34,17 @@ #ifndef QV4INSTR_MOTH_P_H #define QV4INSTR_MOTH_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/qglobal.h> #include <private/qv4value_p.h> #include <private/qv4function_p.h> @@ -64,12 +75,19 @@ QT_BEGIN_NAMESPACE F(SetLookup, setLookup) \ F(StoreQObjectProperty, storeQObjectProperty) \ F(LoadQObjectProperty, loadQObjectProperty) \ + F(StoreScopeObjectProperty, storeScopeObjectProperty) \ + F(StoreContextObjectProperty, storeContextObjectProperty) \ + F(LoadScopeObjectProperty, loadScopeObjectProperty) \ + F(LoadContextObjectProperty, loadContextObjectProperty) \ + F(LoadIdObject, loadIdObject) \ F(LoadAttachedQObjectProperty, loadAttachedQObjectProperty) \ F(LoadSingletonQObjectProperty, loadQObjectProperty) \ F(Push, push) \ F(CallValue, callValue) \ F(CallProperty, callProperty) \ F(CallPropertyLookup, callPropertyLookup) \ + F(CallScopeObjectProperty, callScopeObjectProperty) \ + F(CallContextObjectProperty, callContextObjectProperty) \ F(CallElement, callElement) \ F(CallActivationProperty, callActivationProperty) \ F(CallGlobalLookup, callGlobalLookup) \ @@ -84,6 +102,8 @@ QT_BEGIN_NAMESPACE F(CallBuiltinDeleteMember, callBuiltinDeleteMember) \ F(CallBuiltinDeleteSubscript, callBuiltinDeleteSubscript) \ F(CallBuiltinDeleteName, callBuiltinDeleteName) \ + F(CallBuiltinTypeofScopeObjectProperty, callBuiltinTypeofScopeObjectProperty) \ + F(CallBuiltinTypeofContextObjectProperty, callBuiltinTypeofContextObjectProperty) \ F(CallBuiltinTypeofMember, callBuiltinTypeofMember) \ F(CallBuiltinTypeofSubscript, callBuiltinTypeofSubscript) \ F(CallBuiltinTypeofName, callBuiltinTypeofName) \ @@ -125,10 +145,8 @@ QT_BEGIN_NAMESPACE F(Sub, sub) \ F(BinopContext, binopContext) \ F(LoadThis, loadThis) \ - F(LoadQmlIdArray, loadQmlIdArray) \ + F(LoadQmlContext, loadQmlContext) \ F(LoadQmlImportedScripts, loadQmlImportedScripts) \ - F(LoadQmlContextObject, loadQmlContextObject) \ - F(LoadQmlScopeObject, loadQmlScopeObject) \ F(LoadQmlSingleton, loadQmlSingleton) #if defined(Q_CC_GNU) && (!defined(Q_CC_INTEL) || __INTEL_COMPILER >= 1200) @@ -293,6 +311,24 @@ union Instr Param base; Param result; }; + struct instr_loadScopeObjectProperty { + MOTH_INSTR_HEADER + int propertyIndex; + Param base; + Param result; + }; + struct instr_loadContextObjectProperty { + MOTH_INSTR_HEADER + int propertyIndex; + Param base; + Param result; + }; + struct instr_loadIdObject { + MOTH_INSTR_HEADER + int index; + Param base; + Param result; + }; struct instr_loadQObjectProperty { MOTH_INSTR_HEADER int propertyIndex; @@ -318,6 +354,18 @@ union Instr Param base; Param source; }; + struct instr_storeScopeObjectProperty { + MOTH_INSTR_HEADER + Param base; + int propertyIndex; + Param source; + }; + struct instr_storeContextObjectProperty { + MOTH_INSTR_HEADER + Param base; + int propertyIndex; + Param source; + }; struct instr_storeQObjectProperty { MOTH_INSTR_HEADER Param base; @@ -377,6 +425,22 @@ union Instr Param base; Param result; }; + struct instr_callScopeObjectProperty { + MOTH_INSTR_HEADER + int index; + quint32 argc; + quint32 callData; + Param base; + Param result; + }; + struct instr_callContextObjectProperty { + MOTH_INSTR_HEADER + int index; + quint32 argc; + quint32 callData; + Param base; + Param result; + }; struct instr_callElement { MOTH_INSTR_HEADER Param base; @@ -449,6 +513,18 @@ union Instr int name; Param result; }; + struct instr_callBuiltinTypeofScopeObjectProperty { + MOTH_INSTR_HEADER + int index; + Param base; + Param result; + }; + struct instr_callBuiltinTypeofContextObjectProperty { + MOTH_INSTR_HEADER + int index; + Param base; + Param result; + }; struct instr_callBuiltinTypeofMember { MOTH_INSTR_HEADER int member; @@ -684,7 +760,7 @@ union Instr MOTH_INSTR_HEADER Param result; }; - struct instr_loadQmlIdArray { + struct instr_loadQmlContext { MOTH_INSTR_HEADER Param result; }; @@ -692,14 +768,6 @@ union Instr MOTH_INSTR_HEADER Param result; }; - struct instr_loadQmlContextObject { - MOTH_INSTR_HEADER - Param result; - }; - struct instr_loadQmlScopeObject { - MOTH_INSTR_HEADER - Param result; - }; struct instr_loadQmlSingleton { MOTH_INSTR_HEADER Param result; @@ -725,15 +793,22 @@ union Instr instr_storeElementLookup storeElementLookup; instr_loadProperty loadProperty; instr_getLookup getLookup; + instr_loadScopeObjectProperty loadScopeObjectProperty; + instr_loadContextObjectProperty loadContextObjectProperty; + instr_loadIdObject loadIdObject; instr_loadQObjectProperty loadQObjectProperty; instr_loadAttachedQObjectProperty loadAttachedQObjectProperty; instr_storeProperty storeProperty; instr_setLookup setLookup; + instr_storeScopeObjectProperty storeScopeObjectProperty; + instr_storeContextObjectProperty storeContextObjectProperty; instr_storeQObjectProperty storeQObjectProperty; instr_push push; instr_callValue callValue; instr_callProperty callProperty; instr_callPropertyLookup callPropertyLookup; + instr_callScopeObjectProperty callScopeObjectProperty; + instr_callContextObjectProperty callContextObjectProperty; instr_callElement callElement; instr_callActivationProperty callActivationProperty; instr_callGlobalLookup callGlobalLookup; @@ -748,6 +823,8 @@ union Instr instr_callBuiltinDeleteMember callBuiltinDeleteMember; instr_callBuiltinDeleteSubscript callBuiltinDeleteSubscript; instr_callBuiltinDeleteName callBuiltinDeleteName; + instr_callBuiltinTypeofScopeObjectProperty callBuiltinTypeofScopeObjectProperty; + instr_callBuiltinTypeofContextObjectProperty callBuiltinTypeofContextObjectProperty; instr_callBuiltinTypeofMember callBuiltinTypeofMember; instr_callBuiltinTypeofSubscript callBuiltinTypeofSubscript; instr_callBuiltinTypeofName callBuiltinTypeofName; @@ -789,10 +866,8 @@ union Instr instr_sub sub; instr_binopContext binopContext; instr_loadThis loadThis; - instr_loadQmlIdArray loadQmlIdArray; + instr_loadQmlContext loadQmlContext; instr_loadQmlImportedScripts loadQmlImportedScripts; - instr_loadQmlContextObject loadQmlContextObject; - instr_loadQmlScopeObject loadQmlScopeObject; instr_loadQmlSingleton loadQmlSingleton; static int size(Type type); diff --git a/src/qml/compiler/qv4isel_moth.cpp b/src/qml/compiler/qv4isel_moth.cpp index eb78a0c054..afb36c5f14 100644 --- a/src/qml/compiler/qv4isel_moth.cpp +++ b/src/qml/compiler/qv4isel_moth.cpp @@ -350,7 +350,7 @@ void InstructionSelection::run(int functionIndex) opt.run(qmlEngine, useTypeInference, /*peelLoops =*/ false); if (opt.isInSSA()) { static const bool doStackSlotAllocation = - qgetenv("QV4_NO_INTERPRETER_STACK_SLOT_ALLOCATION").isEmpty(); + qEnvironmentVariableIsEmpty("QV4_NO_INTERPRETER_STACK_SLOT_ALLOCATION"); if (doStackSlotAllocation) { AllocateStackSlots(opt.lifeTimeIntervals()).forFunction(_function); @@ -447,7 +447,7 @@ QQmlRefPointer<QV4::CompiledData::CompilationUnit> InstructionSelection::backend foreach (IR::Function *irFunction, irModule->functions) compilationUnit->codeRefs[i++] = codeRefs[irFunction]; QQmlRefPointer<QV4::CompiledData::CompilationUnit> result; - result.take(compilationUnit.take()); + result.adopt(compilationUnit.take()); return result; } @@ -461,6 +461,29 @@ void InstructionSelection::callValue(IR::Expr *value, IR::ExprList *args, IR::Ex addInstruction(call); } +void InstructionSelection::callQmlContextProperty(IR::Expr *base, IR::Member::MemberKind kind, int propertyIndex, IR::ExprList *args, IR::Expr *result) +{ + if (kind == IR::Member::MemberOfQmlScopeObject) { + Instruction::CallScopeObjectProperty call; + call.base = getParam(base); + call.index = propertyIndex; + prepareCallArgs(args, call.argc); + call.callData = callDataStart(); + call.result = getResultParam(result); + addInstruction(call); + } else if (kind == IR::Member::MemberOfQmlContextObject) { + Instruction::CallContextObjectProperty call; + call.base = getParam(base); + call.index = propertyIndex; + prepareCallArgs(args, call.argc); + call.callData = callDataStart(); + call.result = getResultParam(result); + addInstruction(call); + } else { + Q_ASSERT(false); + } +} + void InstructionSelection::callProperty(IR::Expr *base, const QString &name, IR::ExprList *args, IR::Expr *result) { @@ -565,9 +588,9 @@ void InstructionSelection::loadThisObject(IR::Expr *e) addInstruction(load); } -void InstructionSelection::loadQmlIdArray(IR::Expr *e) +void InstructionSelection::loadQmlContext(IR::Expr *e) { - Instruction::LoadQmlIdArray load; + Instruction::LoadQmlContext load; load.result = getResultParam(e); addInstruction(load); } @@ -579,20 +602,6 @@ void InstructionSelection::loadQmlImportedScripts(IR::Expr *e) addInstruction(load); } -void InstructionSelection::loadQmlContextObject(IR::Expr *e) -{ - Instruction::LoadQmlContextObject load; - load.result = getResultParam(e); - addInstruction(load); -} - -void InstructionSelection::loadQmlScopeObject(IR::Expr *e) -{ - Instruction::LoadQmlScopeObject load; - load.result = getResultParam(e); - addInstruction(load); -} - void InstructionSelection::loadQmlSingleton(const QString &name, IR::Expr *e) { Instruction::LoadQmlSingleton load; @@ -694,6 +703,25 @@ void InstructionSelection::setProperty(IR::Expr *source, IR::Expr *targetBase, addInstruction(store); } +void InstructionSelection::setQmlContextProperty(IR::Expr *source, IR::Expr *targetBase, IR::Member::MemberKind kind, int propertyIndex) +{ + if (kind == IR::Member::MemberOfQmlScopeObject) { + Instruction::StoreScopeObjectProperty store; + store.base = getParam(targetBase); + store.propertyIndex = propertyIndex; + store.source = getParam(source); + addInstruction(store); + } else if (kind == IR::Member::MemberOfQmlContextObject) { + Instruction::StoreContextObjectProperty store; + store.base = getParam(targetBase); + store.propertyIndex = propertyIndex; + store.source = getParam(source); + addInstruction(store); + } else { + Q_ASSERT(false); + } +} + void InstructionSelection::setQObjectProperty(IR::Expr *source, IR::Expr *targetBase, int propertyIndex) { Instruction::StoreQObjectProperty store; @@ -703,6 +731,31 @@ void InstructionSelection::setQObjectProperty(IR::Expr *source, IR::Expr *target addInstruction(store); } +void InstructionSelection::getQmlContextProperty(IR::Expr *source, IR::Member::MemberKind kind, int index, IR::Expr *target) +{ + if (kind == IR::Member::MemberOfQmlScopeObject) { + Instruction::LoadScopeObjectProperty load; + load.base = getParam(source); + load.propertyIndex = index; + load.result = getResultParam(target); + addInstruction(load); + } else if (kind == IR::Member::MemberOfQmlContextObject) { + Instruction::LoadContextObjectProperty load; + load.base = getParam(source); + load.propertyIndex = index; + load.result = getResultParam(target); + addInstruction(load); + } else if (kind == IR::Member::MemberOfIdObjectsArray) { + Instruction::LoadIdObject load; + load.base = getParam(source); + load.index = index; + load.result = getResultParam(target); + addInstruction(load); + } else { + Q_ASSERT(false); + } +} + void InstructionSelection::getQObjectProperty(IR::Expr *base, int propertyIndex, bool captureRequired, bool isSingletonProperty, int attachedPropertiesId, IR::Expr *target) { if (attachedPropertiesId != 0) { @@ -1124,6 +1177,25 @@ void InstructionSelection::callBuiltinInvalid(IR::Name *func, IR::ExprList *args addInstruction(call); } +void InstructionSelection::callBuiltinTypeofQmlContextProperty(IR::Expr *base, IR::Member::MemberKind kind, int propertyIndex, IR::Expr *result) +{ + if (kind == IR::Member::MemberOfQmlScopeObject) { + Instruction::CallBuiltinTypeofScopeObjectProperty call; + call.base = getParam(base); + call.index = propertyIndex; + call.result = getResultParam(result); + addInstruction(call); + } else if (kind == IR::Member::MemberOfQmlContextObject) { + Instruction::CallBuiltinTypeofContextObjectProperty call; + call.base = getParam(base); + call.index = propertyIndex; + call.result = getResultParam(result); + addInstruction(call); + } else { + Q_UNREACHABLE(); + } +} + void InstructionSelection::callBuiltinTypeofMember(IR::Expr *base, const QString &name, IR::Expr *result) { @@ -1444,7 +1516,7 @@ ptrdiff_t InstructionSelection::addInstructionHelper(Instr::Type type, Instr &in void InstructionSelection::patchJumpAddresses() { typedef QHash<IR::BasicBlock *, QVector<ptrdiff_t> >::ConstIterator PatchIt; - for (PatchIt i = _patches.begin(), ei = _patches.end(); i != ei; ++i) { + for (PatchIt i = _patches.cbegin(), ei = _patches.cend(); i != ei; ++i) { Q_ASSERT(_addrs.contains(i.key())); ptrdiff_t target = _addrs.value(i.key()); diff --git a/src/qml/compiler/qv4isel_moth_p.h b/src/qml/compiler/qv4isel_moth_p.h index 4ea0f1d07f..e2385aad6d 100644 --- a/src/qml/compiler/qv4isel_moth_p.h +++ b/src/qml/compiler/qv4isel_moth_p.h @@ -34,6 +34,17 @@ #ifndef QV4ISEL_MOTH_P_H #define QV4ISEL_MOTH_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/qv4global_p.h> #include <private/qv4isel_p.h> #include <private/qv4isel_util_p.h> @@ -73,6 +84,7 @@ protected: virtual void visitRet(IR::Ret *); virtual void callBuiltinInvalid(IR::Name *func, IR::ExprList *args, IR::Expr *result); + virtual void callBuiltinTypeofQmlContextProperty(IR::Expr *base, IR::Member::MemberKind kind, int propertyIndex, IR::Expr *result); virtual void callBuiltinTypeofMember(IR::Expr *base, const QString &name, IR::Expr *result); virtual void callBuiltinTypeofSubscript(IR::Expr *base, IR::Expr *index, IR::Expr *result); virtual void callBuiltinTypeofName(const QString &name, IR::Expr *result); @@ -95,6 +107,7 @@ protected: virtual void callBuiltinSetupArgumentObject(IR::Expr *result); virtual void callBuiltinConvertThisToObject(); virtual void callValue(IR::Expr *value, IR::ExprList *args, IR::Expr *result); + virtual void callQmlContextProperty(IR::Expr *base, IR::Member::MemberKind kind, int propertyIndex, IR::ExprList *args, IR::Expr *result); virtual void callProperty(IR::Expr *base, const QString &name, IR::ExprList *args, IR::Expr *result); virtual void callSubscript(IR::Expr *base, IR::Expr *index, IR::ExprList *args, IR::Expr *result); virtual void convertType(IR::Expr *source, IR::Expr *target); @@ -102,10 +115,8 @@ protected: virtual void constructProperty(IR::Expr *base, const QString &name, IR::ExprList *args, IR::Expr *result); virtual void constructValue(IR::Expr *value, IR::ExprList *args, IR::Expr *result); virtual void loadThisObject(IR::Expr *e); - virtual void loadQmlIdArray(IR::Expr *e); + virtual void loadQmlContext(IR::Expr *e); virtual void loadQmlImportedScripts(IR::Expr *e); - virtual void loadQmlContextObject(IR::Expr *e); - virtual void loadQmlScopeObject(IR::Expr *e); virtual void loadQmlSingleton(const QString &name, IR::Expr *e); virtual void loadConst(IR::Const *sourceConst, IR::Expr *e); virtual void loadString(const QString &str, IR::Expr *target); @@ -115,7 +126,9 @@ protected: virtual void initClosure(IR::Closure *closure, IR::Expr *target); virtual void getProperty(IR::Expr *base, const QString &name, IR::Expr *target); virtual void setProperty(IR::Expr *source, IR::Expr *targetBase, const QString &targetName); + virtual void setQmlContextProperty(IR::Expr *source, IR::Expr *targetBase, IR::Member::MemberKind kind, int propertyIndex); virtual void setQObjectProperty(IR::Expr *source, IR::Expr *targetBase, int propertyIndex); + virtual void getQmlContextProperty(IR::Expr *source, IR::Member::MemberKind kind, int index, IR::Expr *target); virtual void getQObjectProperty(IR::Expr *base, int propertyIndex, bool captureRequired, bool isSingleton, int attachedPropertiesId, IR::Expr *target); virtual void getElement(IR::Expr *base, IR::Expr *index, IR::Expr *target); virtual void setElement(IR::Expr *source, IR::Expr *targetBase, IR::Expr *targetIndex); diff --git a/src/qml/compiler/qv4isel_p.cpp b/src/qml/compiler/qv4isel_p.cpp index 54b184b4eb..184cff43e6 100644 --- a/src/qml/compiler/qv4isel_p.cpp +++ b/src/qml/compiler/qv4isel_p.cpp @@ -36,7 +36,7 @@ #include "qv4jsir_p.h" #include "qv4isel_p.h" #include "qv4isel_util_p.h" -#include <private/qv4value_inl_p.h> +#include <private/qv4value_p.h> #ifndef V4_BOOTSTRAP #include <private/qqmlpropertycache_p.h> #endif @@ -91,12 +91,8 @@ void IRDecoder::visitMove(IR::Move *s) if (IR::Name *n = s->source->asName()) { if (n->id && *n->id == QStringLiteral("this")) // TODO: `this' should be a builtin. loadThisObject(s->target); - else if (n->builtin == IR::Name::builtin_qml_id_array) - loadQmlIdArray(s->target); - else if (n->builtin == IR::Name::builtin_qml_context_object) - loadQmlContextObject(s->target); - else if (n->builtin == IR::Name::builtin_qml_scope_object) - loadQmlScopeObject(s->target); + else if (n->builtin == IR::Name::builtin_qml_context) + loadQmlContext(s->target); else if (n->builtin == IR::Name::builtin_qml_imported_scripts_object) loadQmlImportedScripts(s->target); else if (n->qmlSingleton) @@ -140,8 +136,8 @@ void IRDecoder::visitMove(IR::Move *s) #else bool captureRequired = true; - Q_ASSERT(m->kind != IR::Member::MemberOfEnum); - const int attachedPropertiesId = m->attachedPropertiesIdOrEnumValue; + Q_ASSERT(m->kind != IR::Member::MemberOfEnum && m->kind != IR::Member::MemberOfIdObjectsArray); + const int attachedPropertiesId = m->attachedPropertiesId; const bool isSingletonProperty = m->kind == IR::Member::MemberOfSingletonObject; if (_function && attachedPropertiesId == 0 && !m->property->isConstant()) { @@ -153,9 +149,16 @@ void IRDecoder::visitMove(IR::Move *s) captureRequired = false; } } + if (m->kind == IR::Member::MemberOfQmlScopeObject || m->kind == IR::Member::MemberOfQmlContextObject) { + getQmlContextProperty(m->base, (IR::Member::MemberKind)m->kind, m->property->coreIndex, s->target); + return; + } getQObjectProperty(m->base, m->property->coreIndex, captureRequired, isSingletonProperty, attachedPropertiesId, s->target); #endif // V4_BOOTSTRAP return; + } else if (m->kind == IR::Member::MemberOfIdObjectsArray) { + getQmlContextProperty(m->base, (IR::Member::MemberKind)m->kind, m->idIndex, s->target); + return; } else if (m->base->asTemp() || m->base->asConst() || m->base->asArgLocal()) { getProperty(m->base, *m->name, s->target); return; @@ -174,6 +177,13 @@ void IRDecoder::visitMove(IR::Move *s) callBuiltin(c, s->target); return; } else if (Member *member = c->base->asMember()) { +#ifndef V4_BOOTSTRAP + Q_ASSERT(member->kind != IR::Member::MemberOfIdObjectsArray); + if (member->kind == IR::Member::MemberOfQmlScopeObject || member->kind == IR::Member::MemberOfQmlContextObject) { + callQmlContextProperty(member->base, (IR::Member::MemberKind)member->kind, member->property->coreIndex, c->args, s->target); + return; + } +#endif callProperty(member->base, *member->name, c->args, s->target); return; } else if (Subscript *ss = c->base->asSubscript()) { @@ -192,11 +202,16 @@ void IRDecoder::visitMove(IR::Move *s) if (m->base->asTemp() || m->base->asConst() || m->base->asArgLocal()) { if (s->source->asTemp() || s->source->asConst() || s->source->asArgLocal()) { Q_ASSERT(m->kind != IR::Member::MemberOfEnum); - const int attachedPropertiesId = m->attachedPropertiesIdOrEnumValue; + Q_ASSERT(m->kind != IR::Member::MemberOfIdObjectsArray); + const int attachedPropertiesId = m->attachedPropertiesId; if (m->property && attachedPropertiesId == 0) { #ifdef V4_BOOTSTRAP Q_UNIMPLEMENTED(); #else + if (m->kind == IR::Member::MemberOfQmlScopeObject || m->kind == IR::Member::MemberOfQmlContextObject) { + setQmlContextProperty(s->source, m->base, (IR::Member::MemberKind)m->kind, m->property->coreIndex); + return; + } setQObjectProperty(s->source, m->base, m->property->coreIndex); #endif return; @@ -238,6 +253,13 @@ void IRDecoder::visitExp(IR::Exp *s) callValue(c->base, c->args, 0); } else if (Member *member = c->base->asMember()) { Q_ASSERT(member->base->asTemp() || member->base->asArgLocal()); +#ifndef V4_BOOTSTRAP + Q_ASSERT(member->kind != IR::Member::MemberOfIdObjectsArray); + if (member->kind == IR::Member::MemberOfQmlScopeObject || member->kind == IR::Member::MemberOfQmlContextObject) { + callQmlContextProperty(member->base, (IR::Member::MemberKind)member->kind, member->property->coreIndex, c->args, 0); + return; + } +#endif callProperty(member->base, *member->name, c->args, 0); } else if (Subscript *s = c->base->asSubscript()) { callSubscript(s->base, s->index, c->args, 0); @@ -260,8 +282,17 @@ void IRDecoder::callBuiltin(IR::Call *call, Expr *result) return; case IR::Name::builtin_typeof: { - if (IR::Member *m = call->args->expr->asMember()) { - callBuiltinTypeofMember(m->base, *m->name, result); + if (IR::Member *member = call->args->expr->asMember()) { +#ifndef V4_BOOTSTRAP + Q_ASSERT(member->kind != IR::Member::MemberOfIdObjectsArray); + if (member->kind == IR::Member::MemberOfQmlScopeObject || member->kind == IR::Member::MemberOfQmlContextObject) { + callBuiltinTypeofQmlContextProperty(member->base, + IR::Member::MemberKind(member->kind), + member->property->coreIndex, result); + return; + } +#endif + callBuiltinTypeofMember(member->base, *member->name, result); return; } else if (IR::Subscript *ss = call->args->expr->asSubscript()) { callBuiltinTypeofSubscript(ss->base, ss->index, result); diff --git a/src/qml/compiler/qv4isel_p.h b/src/qml/compiler/qv4isel_p.h index 1e273df93e..b78d323e7d 100644 --- a/src/qml/compiler/qv4isel_p.h +++ b/src/qml/compiler/qv4isel_p.h @@ -34,6 +34,17 @@ #ifndef QV4ISEL_P_H #define QV4ISEL_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/qv4global_p.h" #include "qv4jsir_p.h" #include <private/qv4compileddata_p.h> @@ -107,6 +118,7 @@ public: // visitor methods for StmtVisitor: public: // to implement by subclasses: virtual void callBuiltinInvalid(IR::Name *func, IR::ExprList *args, IR::Expr *result) = 0; + virtual void callBuiltinTypeofQmlContextProperty(IR::Expr *base, IR::Member::MemberKind kind, int propertyIndex, IR::Expr *result) = 0; virtual void callBuiltinTypeofMember(IR::Expr *base, const QString &name, IR::Expr *result) = 0; virtual void callBuiltinTypeofSubscript(IR::Expr *base, IR::Expr *index, IR::Expr *result) = 0; virtual void callBuiltinTypeofName(const QString &name, IR::Expr *result) = 0; @@ -129,6 +141,7 @@ public: // to implement by subclasses: virtual void callBuiltinSetupArgumentObject(IR::Expr *result) = 0; virtual void callBuiltinConvertThisToObject() = 0; virtual void callValue(IR::Expr *value, IR::ExprList *args, IR::Expr *result) = 0; + virtual void callQmlContextProperty(IR::Expr *base, IR::Member::MemberKind kind, int propertyIndex, IR::ExprList *args, IR::Expr *result) = 0; virtual void callProperty(IR::Expr *base, const QString &name, IR::ExprList *args, IR::Expr *result) = 0; virtual void callSubscript(IR::Expr *base, IR::Expr *index, IR::ExprList *args, IR::Expr *result) = 0; virtual void convertType(IR::Expr *source, IR::Expr *target) = 0; @@ -136,10 +149,8 @@ public: // to implement by subclasses: virtual void constructProperty(IR::Expr *base, const QString &name, IR::ExprList *args, IR::Expr *result) = 0; virtual void constructValue(IR::Expr *value, IR::ExprList *args, IR::Expr *result) = 0; virtual void loadThisObject(IR::Expr *target) = 0; - virtual void loadQmlIdArray(IR::Expr *target) = 0; + virtual void loadQmlContext(IR::Expr *target) = 0; virtual void loadQmlImportedScripts(IR::Expr *target) = 0; - virtual void loadQmlContextObject(IR::Expr *target) = 0; - virtual void loadQmlScopeObject(IR::Expr *target) = 0; virtual void loadQmlSingleton(const QString &name, IR::Expr *target) = 0; virtual void loadConst(IR::Const *sourceConst, IR::Expr *target) = 0; virtual void loadString(const QString &str, IR::Expr *target) = 0; @@ -149,7 +160,9 @@ public: // to implement by subclasses: virtual void initClosure(IR::Closure *closure, IR::Expr *target) = 0; virtual void getProperty(IR::Expr *base, const QString &name, IR::Expr *target) = 0; virtual void getQObjectProperty(IR::Expr *base, int propertyIndex, bool captureRequired, bool isSingletonProperty, int attachedPropertiesId, IR::Expr *target) = 0; + virtual void getQmlContextProperty(IR::Expr *source, IR::Member::MemberKind kind, int index, IR::Expr *target) = 0; virtual void setProperty(IR::Expr *source, IR::Expr *targetBase, const QString &targetName) = 0; + virtual void setQmlContextProperty(IR::Expr *source, IR::Expr *targetBase, IR::Member::MemberKind kind, int propertyIndex) = 0; virtual void setQObjectProperty(IR::Expr *source, IR::Expr *targetBase, int propertyIndex) = 0; virtual void getElement(IR::Expr *base, IR::Expr *index, IR::Expr *target) = 0; virtual void setElement(IR::Expr *source, IR::Expr *targetBase, IR::Expr *targetIndex) = 0; diff --git a/src/qml/compiler/qv4isel_util_p.h b/src/qml/compiler/qv4isel_util_p.h index 521c345228..9c4ab63ba6 100644 --- a/src/qml/compiler/qv4isel_util_p.h +++ b/src/qml/compiler/qv4isel_util_p.h @@ -34,6 +34,17 @@ #ifndef QV4ISEL_UTIL_P_H #define QV4ISEL_UTIL_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/qv4value_p.h" #include "qv4jsir_p.h" diff --git a/src/qml/compiler/qv4jsir.cpp b/src/qml/compiler/qv4jsir.cpp index 5c9cc98ade..685825e8ea 100644 --- a/src/qml/compiler/qv4jsir.cpp +++ b/src/qml/compiler/qv4jsir.cpp @@ -175,8 +175,8 @@ struct RemoveSharedExpressions: IR::StmtVisitor, IR::ExprVisitor } } - template <typename _Expr> - _Expr *cleanup(_Expr *expr) + template <typename Expr_> + Expr_ *cleanup(Expr_ *expr) { std::vector<Expr *>::iterator it = std::lower_bound(subexpressions.begin(), subexpressions.end(), expr); if (it == subexpressions.end() || *it != expr) { @@ -185,7 +185,7 @@ struct RemoveSharedExpressions: IR::StmtVisitor, IR::ExprVisitor qSwap(uniqueExpr, e); expr->accept(this); qSwap(uniqueExpr, e); - return static_cast<_Expr *>(e); + return static_cast<Expr_ *>(e); } // the cloned expression is unique by definition @@ -341,14 +341,10 @@ const char *builtin_to_string(Name::Builtin b) return "builtin_setup_argument_object"; case IR::Name::builtin_convert_this_to_object: return "builtin_convert_this_to_object"; - case IR::Name::builtin_qml_id_array: - return "builtin_qml_id_array"; + case IR::Name::builtin_qml_context: + return "builtin_qml_context"; case IR::Name::builtin_qml_imported_scripts_object: return "builtin_qml_imported_scripts_object"; - case IR::Name::builtin_qml_scope_object: - return "builtin_qml_scope_object"; - case IR::Name::builtin_qml_context_object: - return "builtin_qml_context_object"; } return "builtin_(###FIXME)"; }; @@ -935,7 +931,7 @@ void CloneExpr::visitSubscript(Subscript *e) void CloneExpr::visitMember(Member *e) { Expr *clonedBase = clone(e->base); - cloned = block->MEMBER(clonedBase, e->name, e->property, e->kind, e->attachedPropertiesIdOrEnumValue); + cloned = block->MEMBER(clonedBase, e->name, e->property, e->kind, e->idIndex); } IRPrinter::IRPrinter(QTextStream *out) @@ -1239,9 +1235,9 @@ void IRPrinter::visitSubscript(Subscript *e) void IRPrinter::visitMember(Member *e) { - if (e->kind != Member::MemberOfEnum - && e->attachedPropertiesIdOrEnumValue != 0 && !e->base->asTemp()) - *out << "[[attached property from " << e->attachedPropertiesIdOrEnumValue << "]]"; + if (e->kind != Member::MemberOfEnum && e->kind != Member::MemberOfIdObjectsArray + && e->attachedPropertiesId != 0 && !e->base->asTemp()) + *out << "[[attached property from " << e->attachedPropertiesId << "]]"; else e->base->accept(this); *out << '.' << *e->name; @@ -1250,6 +1246,8 @@ void IRPrinter::visitMember(Member *e) *out << " (meta-property " << e->property->coreIndex << " <" << QMetaType::typeName(e->property->propType) << ">)"; + else if (e->kind == Member::MemberOfIdObjectsArray) + *out << "(id object " << e->idIndex << ")"; #endif } diff --git a/src/qml/compiler/qv4jsir_p.h b/src/qml/compiler/qv4jsir_p.h index 8daad97e8b..80869dd3e3 100644 --- a/src/qml/compiler/qv4jsir_p.h +++ b/src/qml/compiler/qv4jsir_p.h @@ -53,6 +53,7 @@ #include <QtCore/QString> #include <QtCore/QBitArray> #include <QtCore/qurl.h> +#include <QtCore/QVarLengthArray> #include <qglobal.h> #if defined(CONST) && defined(Q_OS_WIN) @@ -114,6 +115,23 @@ struct CJump; struct Ret; struct Phi; +template<class T, int Prealloc> +class VarLengthArray: public QVarLengthArray<T, Prealloc> +{ +public: + bool removeOne(const T &element) + { + for (int i = 0; i < this->size(); ++i) { + if (this->at(i) == element) { + this->remove(i); + return true; + } + } + + return false; + } +}; + // Flag pointer: // * The first flag indicates whether the meta object is final. // If final, then none of its properties themselves need to @@ -337,10 +355,8 @@ struct Name: Expr { builtin_define_object_literal, builtin_setup_argument_object, builtin_convert_this_to_object, - builtin_qml_id_array, - builtin_qml_imported_scripts_object, - builtin_qml_context_object, - builtin_qml_scope_object + builtin_qml_context, + builtin_qml_imported_scripts_object }; const QString *id; @@ -368,18 +384,18 @@ struct Q_AUTOTEST_EXPORT Temp: Expr { StackSlot }; - // Used when temp is used as base in member expression - MemberExpressionResolver *memberResolver; - unsigned index : 28; unsigned isReadOnly : 1; unsigned kind : 3; + // Used when temp is used as base in member expression + MemberExpressionResolver *memberResolver; + Temp() - : memberResolver(0) - , index((1 << 28) - 1) + : index((1 << 28) - 1) , isReadOnly(0) , kind(Invalid) + , memberResolver(0) {} void init(unsigned kind, unsigned index) @@ -558,13 +574,18 @@ struct Member: Expr { MemberOfEnum, MemberOfQmlScopeObject, MemberOfQmlContextObject, - MemberOfSingletonObject + MemberOfIdObjectsArray, + MemberOfSingletonObject, }; Expr *base; const QString *name; QQmlPropertyData *property; - int attachedPropertiesIdOrEnumValue; // depending on kind + union { // depending on kind + int attachedPropertiesId; + int enumValue; + int idIndex; + }; uchar freeOfSideEffects : 1; // This is set for example for for QObject properties. All sorts of extra behavior @@ -577,20 +598,20 @@ struct Member: Expr { void setEnumValue(int value) { kind = MemberOfEnum; - attachedPropertiesIdOrEnumValue = value; + enumValue = value; } void setAttachedPropertiesId(int id) { - Q_ASSERT(kind != MemberOfEnum); - attachedPropertiesIdOrEnumValue = id; + Q_ASSERT(kind != MemberOfEnum && kind != MemberOfIdObjectsArray); + attachedPropertiesId = id; } - void init(Expr *base, const QString *name, QQmlPropertyData *property = 0, uchar kind = UnspecifiedMember, int attachedPropertiesIdOrEnumValue = 0) + void init(Expr *base, const QString *name, QQmlPropertyData *property = 0, uchar kind = UnspecifiedMember, int index = 0) { this->base = base; this->name = name; this->property = property; - this->attachedPropertiesIdOrEnumValue = attachedPropertiesIdOrEnumValue; + this->idIndex = index; this->freeOfSideEffects = false; this->inhibitTypeConversionOnWrite = property != 0; this->kind = kind; @@ -768,10 +789,13 @@ private: Q_DISABLE_COPY(BasicBlock) public: + typedef VarLengthArray<BasicBlock *, 4> IncomingEdges; + typedef VarLengthArray<BasicBlock *, 2> OutgoingEdges; + Function *function; BasicBlock *catchBlock; - QVector<BasicBlock *> in; - QVector<BasicBlock *> out; + IncomingEdges in; + OutgoingEdges out; QQmlJS::AST::SourceLocation nextLocation; BasicBlock(Function *function, BasicBlock *catcher) @@ -782,10 +806,7 @@ public: , _isExceptionHandler(false) , _groupStart(false) , _isRemoved(false) - { - in.reserve(2); - out.reserve(2); - } + {} ~BasicBlock(); const QVector<Stmt *> &statements() const diff --git a/src/qml/compiler/qv4ssa.cpp b/src/qml/compiler/qv4ssa.cpp index c0669d3e47..f20dbbf4fe 100644 --- a/src/qml/compiler/qv4ssa.cpp +++ b/src/qml/compiler/qv4ssa.cpp @@ -69,7 +69,7 @@ enum { DoVerification = 1 }; static void showMeTheCode(IR::Function *function, const char *marker) { - static bool showCode = !qgetenv("QV4_SHOW_IR").isNull(); + static const bool showCode = qEnvironmentVariableIsSet("QV4_SHOW_IR"); if (showCode) { qDebug() << marker; QBuffer buf; @@ -477,7 +477,7 @@ class DominatorTree d->vertex[d->N] = n; d->parent[n] = todo.parent; ++d->N; - const QVector<BasicBlock *> &out = function->basicBlock(n)->out; + const BasicBlock::OutgoingEdges &out = function->basicBlock(n)->out; for (int i = out.size() - 1; i > 0; --i) worklist.push_back(DFSTodo(out[i]->index(), n)); @@ -2028,32 +2028,16 @@ private: } }; -class EliminateDeadCode: public ExprVisitor { - DefUses &_defUses; - StatementWorklist &_worklist; +class SideEffectsChecker: public ExprVisitor +{ bool _sideEffect; - QVector<Temp *> _collectedTemps; public: - EliminateDeadCode(DefUses &defUses, StatementWorklist &worklist) - : _defUses(defUses) - , _worklist(worklist) - { - _collectedTemps.reserve(8); - } - - void run(Expr *&expr, Stmt *stmt) { - if (!checkForSideEffects(expr)) { - expr = 0; - foreach (Temp *t, _collectedTemps) { - _defUses.removeUse(stmt, *t); - _worklist += _defUses.defStmt(*t); - } - } - } + SideEffectsChecker() + : _sideEffect(false) + {} -private: - bool checkForSideEffects(Expr *expr) + bool hasSideEffects(Expr *expr) { bool sideEffect = false; qSwap(_sideEffect, sideEffect); @@ -2062,19 +2046,20 @@ private: return sideEffect; } +protected: void markAsSideEffect() { _sideEffect = true; - _collectedTemps.clear(); } + bool seenSideEffects() const { return _sideEffect; } + protected: - virtual void visitConst(Const *) {} - virtual void visitString(IR::String *) {} - virtual void visitRegExp(IR::RegExp *) {} + void visitConst(Const *) Q_DECL_OVERRIDE {} + void visitString(IR::String *) Q_DECL_OVERRIDE {} + void visitRegExp(IR::RegExp *) Q_DECL_OVERRIDE {} - virtual void visitName(Name *e) - { + void visitName(Name *e) Q_DECL_OVERRIDE { if (e->freeOfSideEffects) return; // TODO: maybe we can distinguish between built-ins of which we know that they do not have @@ -2083,19 +2068,14 @@ protected: markAsSideEffect(); } - virtual void visitTemp(Temp *e) - { - _collectedTemps.append(e); - } - - virtual void visitArgLocal(ArgLocal *) {} + void visitTemp(Temp *) Q_DECL_OVERRIDE {} + void visitArgLocal(ArgLocal *) Q_DECL_OVERRIDE {} - virtual void visitClosure(Closure *) - { + void visitClosure(Closure *) Q_DECL_OVERRIDE { markAsSideEffect(); } - virtual void visitConvert(Convert *e) { + void visitConvert(Convert *e) Q_DECL_OVERRIDE { e->expr->accept(this); switch (e->expr->type) { @@ -2109,7 +2089,7 @@ protected: } } - virtual void visitUnop(Unop *e) { + void visitUnop(Unop *e) Q_DECL_OVERRIDE { e->expr->accept(this); switch (e->op) { @@ -2127,39 +2107,39 @@ protected: } } - virtual void visitBinop(Binop *e) { + void visitBinop(Binop *e) Q_DECL_OVERRIDE { // TODO: prune parts that don't have a side-effect. For example, in: // function f(x) { +x+1; return 0; } // we can prune the binop and leave the unop/conversion. - _sideEffect = checkForSideEffects(e->left); - _sideEffect |= checkForSideEffects(e->right); + _sideEffect = hasSideEffects(e->left); + _sideEffect |= hasSideEffects(e->right); if (e->left->type == VarType || e->left->type == StringType || e->left->type == QObjectType || e->right->type == VarType || e->right->type == StringType || e->right->type == QObjectType) markAsSideEffect(); } - virtual void visitSubscript(Subscript *e) { + void visitSubscript(Subscript *e) Q_DECL_OVERRIDE { e->base->accept(this); e->index->accept(this); markAsSideEffect(); } - virtual void visitMember(Member *e) { + void visitMember(Member *e) Q_DECL_OVERRIDE { e->base->accept(this); if (e->freeOfSideEffects) return; markAsSideEffect(); } - virtual void visitCall(Call *e) { + void visitCall(Call *e) Q_DECL_OVERRIDE { e->base->accept(this); for (ExprList *args = e->args; args; args = args->next) args->expr->accept(this); markAsSideEffect(); // TODO: there are built-in functions that have no side effect. } - virtual void visitNew(New *e) { + void visitNew(New *e) Q_DECL_OVERRIDE { e->base->accept(this); for (ExprList *args = e->args; args; args = args->next) args->expr->accept(this); @@ -2167,6 +2147,38 @@ protected: } }; +class EliminateDeadCode: public SideEffectsChecker +{ + DefUses &_defUses; + StatementWorklist &_worklist; + QVector<Temp *> _collectedTemps; + +public: + EliminateDeadCode(DefUses &defUses, StatementWorklist &worklist) + : _defUses(defUses) + , _worklist(worklist) + { + _collectedTemps.reserve(8); + } + + void run(Expr *&expr, Stmt *stmt) { + _collectedTemps.clear(); + if (!hasSideEffects(expr)) { + expr = 0; + foreach (Temp *t, _collectedTemps) { + _defUses.removeUse(stmt, *t); + _worklist += _defUses.defStmt(*t); + } + } + } + +protected: + void visitTemp(Temp *e) Q_DECL_OVERRIDE + { + _collectedTemps.append(e); + } +}; + struct DiscoveredType { int type; MemberExpressionResolver *memberResolver; @@ -3504,7 +3516,7 @@ void checkCriticalEdges(QVector<BasicBlock *> basicBlocks) { } #endif -void cleanupBasicBlocks(IR::Function *function) +static void cleanupBasicBlocks(IR::Function *function) { showMeTheCode(function, "Before basic block cleanup"); @@ -3887,7 +3899,7 @@ bool tryOptimizingComparison(Expr *&expr) void cfg2dot(IR::Function *f, const QVector<LoopDetection::LoopInfo *> &loops = QVector<LoopDetection::LoopInfo *>()) { - static bool showCode = !qgetenv("QV4_SHOW_IR").isNull(); + static const bool showCode = qEnvironmentVariableIsSet("QV4_SHOW_IR"); if (!showCode) return; @@ -3912,7 +3924,7 @@ void cfg2dot(IR::Function *f, const QVector<LoopDetection::LoopInfo *> &loops = QString name; if (f->name) name = *f->name; - else name = QString::fromLatin1("%1").arg((unsigned long long)f); + else name = QStringLiteral("%1").arg((unsigned long long)f); qout << "digraph \"" << name << "\" { ordering=out;\n"; foreach (LoopDetection::LoopInfo *l, loops) { @@ -4020,14 +4032,14 @@ void optimizeSSA(StatementWorklist &W, DefUses &defUses, DominatorTree &df) if (Member *member = m->source->asMember()) { if (member->kind == Member::MemberOfEnum) { Const *c = function->New<Const>(); - const int enumValue = member->attachedPropertiesIdOrEnumValue; + const int enumValue = member->enumValue; c->init(SInt32Type, enumValue); replaceUses(targetTemp, c, W); defUses.removeDef(*targetTemp); W.remove(s); defUses.removeUse(s, *member->base->asTemp()); continue; - } else if (member->attachedPropertiesIdOrEnumValue != 0 && member->property && member->base->asTemp()) { + } else if (member->kind != IR::Member::MemberOfIdObjectsArray && member->attachedPropertiesId != 0 && member->property && member->base->asTemp()) { // Attached properties have no dependency on their base. Isel doesn't // need it and we can eliminate the temp used to initialize it. defUses.removeUse(s, *member->base->asTemp()); @@ -4927,6 +4939,39 @@ static void verifyNoPointerSharing(IR::Function *function) V(function); } +class RemoveLineNumbers: public SideEffectsChecker, public StmtVisitor +{ +public: + static void run(IR::Function *function) + { + foreach (BasicBlock *bb, function->basicBlocks()) { + if (bb->isRemoved()) + continue; + + foreach (Stmt *s, bb->statements()) { + if (!hasSideEffects(s)) { + s->location = QQmlJS::AST::SourceLocation(); + } + } + } + } + +private: + static bool hasSideEffects(Stmt *stmt) + { + RemoveLineNumbers checker; + stmt->accept(&checker); + return checker.seenSideEffects(); + } + + void visitExp(Exp *s) Q_DECL_OVERRIDE { s->expr->accept(this); } + void visitMove(Move *s) Q_DECL_OVERRIDE { s->source->accept(this); s->target->accept(this); } + void visitJump(Jump *) Q_DECL_OVERRIDE {} + void visitCJump(CJump *s) Q_DECL_OVERRIDE { s->cond->accept(this); } + void visitRet(Ret *s) Q_DECL_OVERRIDE { s->expr->accept(this); } + void visitPhi(Phi *) Q_DECL_OVERRIDE {} +}; + } // anonymous namespace void LifeTimeInterval::setFrom(int from) { @@ -5150,12 +5195,15 @@ void Optimizer::run(QQmlEnginePrivate *qmlEngine, bool doTypeInference, bool pee cleanupBasicBlocks(function); function->removeSharedExpressions(); - + int statementCount = 0; + foreach (BasicBlock *bb, function->basicBlocks()) + if (!bb->isRemoved()) + statementCount += bb->statementCount(); // showMeTheCode(function); - static bool doSSA = qgetenv("QV4_NO_SSA").isEmpty(); + static bool doSSA = qEnvironmentVariableIsEmpty("QV4_NO_SSA"); - if (!function->hasTry && !function->hasWith && !function->module->debugMode && doSSA) { + if (!function->hasTry && !function->hasWith && !function->module->debugMode && doSSA && statementCount <= 300) { // qout << "SSA for " << (function->name ? qPrintable(*function->name) : "<anonymous>") << endl; ConvertArgLocals(function).toTemps(); @@ -5221,7 +5269,7 @@ void Optimizer::run(QQmlEnginePrivate *qmlEngine, bool doTypeInference, bool pee verifyNoPointerSharing(function); } - static bool doOpt = qgetenv("QV4_NO_OPT").isEmpty(); + static const bool doOpt = qEnvironmentVariableIsEmpty("QV4_NO_OPT"); if (doOpt) { // qout << "Running SSA optimization..." << endl; worklist.reset(); @@ -5259,6 +5307,11 @@ void Optimizer::run(QQmlEnginePrivate *qmlEngine, bool doTypeInference, bool pee checkCriticalEdges(function->basicBlocks()); #endif + if (!function->module->debugMode) { + RemoveLineNumbers::run(function); + showMeTheCode(function, "After line number removal"); + } + // qout << "Finished SSA." << endl; inSSA = true; } else { diff --git a/src/qml/compiler/qv4ssa_p.h b/src/qml/compiler/qv4ssa_p.h index 3cfacaee27..d06774e803 100644 --- a/src/qml/compiler/qv4ssa_p.h +++ b/src/qml/compiler/qv4ssa_p.h @@ -34,6 +34,17 @@ #ifndef QV4SSA_P_H #define QV4SSA_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 "qv4jsir_p.h" #include <QtCore/QSharedPointer> |