diff options
-rw-r--r-- | src/qml/compiler/qqmlcodegenerator.cpp | 93 | ||||
-rw-r--r-- | src/qml/compiler/qqmlcodegenerator_p.h | 3 | ||||
-rw-r--r-- | src/qml/compiler/qv4codegen_p.h | 2 | ||||
-rw-r--r-- | src/qml/compiler/qv4isel_masm.cpp | 5 | ||||
-rw-r--r-- | src/qml/compiler/qv4isel_masm_p.h | 7 | ||||
-rw-r--r-- | src/qml/compiler/qv4isel_moth.cpp | 5 | ||||
-rw-r--r-- | src/qml/compiler/qv4isel_moth_p.h | 8 | ||||
-rw-r--r-- | src/qml/compiler/qv4isel_p.h | 4 | ||||
-rw-r--r-- | src/qml/compiler/qv4jsir.cpp | 13 | ||||
-rw-r--r-- | src/qml/compiler/qv4jsir_p.h | 25 | ||||
-rw-r--r-- | src/qml/compiler/qv4regalloc.cpp | 1 | ||||
-rw-r--r-- | src/qml/compiler/qv4ssa.cpp | 110 | ||||
-rw-r--r-- | src/qml/compiler/qv4ssa_p.h | 3 | ||||
-rw-r--r-- | src/qml/jsruntime/qv4functionobject.cpp | 3 | ||||
-rw-r--r-- | src/qml/jsruntime/qv4script.cpp | 5 | ||||
-rw-r--r-- | src/qml/qml/qqmlcompiler.cpp | 2 | ||||
-rw-r--r-- | src/qml/qml/qqmlengine_p.h | 13 | ||||
-rw-r--r-- | src/qml/qml/qqmltypeloader.cpp | 2 |
18 files changed, 192 insertions, 112 deletions
diff --git a/src/qml/compiler/qqmlcodegenerator.cpp b/src/qml/compiler/qqmlcodegenerator.cpp index c16dd5daea..7d6a5ad1bc 100644 --- a/src/qml/compiler/qqmlcodegenerator.cpp +++ b/src/qml/compiler/qqmlcodegenerator.cpp @@ -1311,47 +1311,55 @@ static QQmlPropertyData *lookupQmlCompliantProperty(QQmlPropertyCache *cache, co return pd; } -V4IR::Expr *JSCodeGen::member(V4IR::Expr *base, const QString *name) -{ - V4IR::Member *baseAsMember = base->asMember(); - if (baseAsMember) { - QQmlPropertyCache *cache = 0; - - if (baseAsMember->type == V4IR::Member::MemberOfQObject - && baseAsMember->property->isQObject()) { - - bool propertySuitable = baseAsMember->property->isFinal(); - - if (!propertySuitable) { - // Properties of the scope or context object do not need to be final, as we - // intend to find the version of a property available at compile time, not at run-time. - if (V4IR::Name *baseName = baseAsMember->base->asName()) - propertySuitable = baseName->builtin == V4IR::Name::builtin_qml_scope_object || baseName->builtin == V4IR::Name::builtin_qml_context_object; - } +static void initMetaObjectResolver(V4IR::MemberExpressionResolver *resolver, QQmlPropertyCache *metaObject); - // Check if it's suitable for caching - if (propertySuitable) - cache = engine->propertyCacheForType(baseAsMember->property->propType); - } else if (baseAsMember->type == V4IR::Member::MemberOfQmlContext) { - // Similarly, properties of an id referenced object also don't need to be final, because - // we intend to find the version of a property available at compile time, not at run-time. - foreach (const IdMapping &mapping, _idObjects) { - if (baseAsMember->memberIndex == mapping.idIndex) { - cache = mapping.type; - break; - } +static V4IR::Type resolveMetaObjectProperty(QQmlEnginePrivate *qmlEngine, V4IR::MemberExpressionResolver *resolver, V4IR::Member *member) +{ + V4IR::Type result = V4IR::VarType; + // Try to resolve members of QObjects in QML mode + if (qmlEngine) { + QQmlPropertyCache *metaObject = static_cast<QQmlPropertyCache*>(resolver->data); + QQmlPropertyData *property = member->property; + + if (!property && metaObject) { + QQmlPropertyData *candidate = metaObject->property(*member->name, /*object*/0, /*context*/0); + if (candidate && candidate->isFinal() && metaObject->isAllowedInRevision(candidate) + && !candidate->isFunction()) { + property = candidate; + member->property = candidate; // Cache for next iteration and isel needs it. } } - if (cache) { - if (QQmlPropertyData *pd = lookupQmlCompliantProperty(cache, *name)) { - const unsigned baseTemp = _block->newTemp(); - move(_block->TEMP(baseTemp), base); - return _block->QML_QOBJECT_PROPERTY(_block->TEMP(baseTemp), name, pd); + if (property) { + // Enums cannot be mapped to IR types, they need to go through the run-time handling + // of accepting strings that will then be converted to the right values. + if (property->isEnum()) + return V4IR::VarType; + + switch (property->propType) { + case QMetaType::Bool: result = V4IR::BoolType; break; + case QMetaType::Int: result = V4IR::SInt32Type; break; + case QMetaType::Double: result = V4IR::DoubleType; break; + case QMetaType::QString: result = V4IR::StringType; break; + default: + if (property->isQObject()) { + if (QQmlPropertyCache *cache = qmlEngine->propertyCacheForType(property->propType)) { + initMetaObjectResolver(resolver, cache); + return V4IR::QObjectType; + } + } + break; } } } - return QQmlJS::Codegen::member(base, name); + resolver->clear(); + return result; +} + +static void initMetaObjectResolver(V4IR::MemberExpressionResolver *resolver, QQmlPropertyCache *metaObject) +{ + resolver->resolveMember = &resolveMetaObjectProperty; + resolver->data = metaObject; } V4IR::Expr *JSCodeGen::fallbackNameLookup(const QString &name, int line, int col) @@ -1393,9 +1401,12 @@ V4IR::Expr *JSCodeGen::fallbackNameLookup(const QString &name, int line, int col if (pd) { if (!pd->isConstant()) _function->scopeObjectDependencies.insert(pd); - int base = _block->newTemp(); - move(_block->TEMP(base), _block->NAME(V4IR::Name::builtin_qml_scope_object, line, col)); - return _block->QML_QOBJECT_PROPERTY(_block->TEMP(base), _function->newString(name), pd); + int temp = _block->newTemp(); + _block->MOVE(_block->TEMP(temp), _block->NAME(V4IR::Name::builtin_qml_scope_object, line, col)); + V4IR::Temp *base = _block->TEMP(temp); + initMetaObjectResolver(&base->memberResolver, _scopeObject); + return _block->QML_QOBJECT_PROPERTY(base, + _function->newString(name), pd); } } @@ -1407,9 +1418,11 @@ V4IR::Expr *JSCodeGen::fallbackNameLookup(const QString &name, int line, int col if (pd) { if (!pd->isConstant()) _function->contextObjectDependencies.insert(pd); - int base = _block->newTemp(); - move(_block->TEMP(base), _block->NAME(V4IR::Name::builtin_qml_context_object, line, col)); - return _block->QML_QOBJECT_PROPERTY(_block->TEMP(base), _function->newString(name), pd); + int temp = _block->newTemp(); + _block->MOVE(_block->TEMP(temp), _block->NAME(V4IR::Name::builtin_qml_context_object, line, col)); + V4IR::Temp *base = _block->TEMP(temp); + initMetaObjectResolver(&base->memberResolver, _contextObject); + return _block->QML_QOBJECT_PROPERTY(base, _function->newString(name), pd); } } diff --git a/src/qml/compiler/qqmlcodegenerator_p.h b/src/qml/compiler/qqmlcodegenerator_p.h index 1cc5b1e2f6..03c69efb80 100644 --- a/src/qml/compiler/qqmlcodegenerator_p.h +++ b/src/qml/compiler/qqmlcodegenerator_p.h @@ -364,9 +364,6 @@ struct Q_QML_EXPORT JSCodeGen : public QQmlJS::Codegen // Returns mapping from input functions to index in V4IR::Module::functions / compiledData->runtimeFunctions QVector<int> generateJSCodeForFunctionsAndBindings(const QList<AST::Node*> &functions, const QHash<int, QString> &functionNames); - // Resolve QObject members with the help of QQmlEngine's meta type registry - virtual V4IR::Expr *member(V4IR::Expr *base, const QString *name); - protected: virtual V4IR::Expr *fallbackNameLookup(const QString &name, int line, int col); diff --git a/src/qml/compiler/qv4codegen_p.h b/src/qml/compiler/qv4codegen_p.h index de22e8904b..736ac9871d 100644 --- a/src/qml/compiler/qv4codegen_p.h +++ b/src/qml/compiler/qv4codegen_p.h @@ -293,7 +293,7 @@ protected: _exceptionHandlers.pop(); } - virtual V4IR::Expr *member(V4IR::Expr *base, const QString *name); // Re-implemented by QML to resolve QObject property members + V4IR::Expr *member(V4IR::Expr *base, const QString *name); V4IR::Expr *subscript(V4IR::Expr *base, V4IR::Expr *index); V4IR::Expr *argument(V4IR::Expr *expr); V4IR::Expr *reference(V4IR::Expr *expr); diff --git a/src/qml/compiler/qv4isel_masm.cpp b/src/qml/compiler/qv4isel_masm.cpp index aca28eac2c..6f8bf13bd7 100644 --- a/src/qml/compiler/qv4isel_masm.cpp +++ b/src/qml/compiler/qv4isel_masm.cpp @@ -539,10 +539,11 @@ JSC::MacroAssemblerCodeRef Assembler::link(int *codeSize) return codeRef; } -InstructionSelection::InstructionSelection(QV4::ExecutableAllocator *execAllocator, V4IR::Module *module, Compiler::JSUnitGenerator *jsGenerator) +InstructionSelection::InstructionSelection(QQmlEnginePrivate *qmlEngine, QV4::ExecutableAllocator *execAllocator, V4IR::Module *module, Compiler::JSUnitGenerator *jsGenerator) : EvalInstructionSelection(execAllocator, module, jsGenerator) , _block(0) , _as(0) + , qmlEngine(qmlEngine) { compilationUnit = new CompilationUnit; compilationUnit->codeRefs.resize(module->functions.size()); @@ -561,7 +562,7 @@ void InstructionSelection::run(int functionIndex) qSwap(_function, function); V4IR::Optimizer opt(_function); - opt.run(); + opt.run(qmlEngine); #if (CPU(X86_64) && (OS(MAC_OS_X) || OS(LINUX))) || (CPU(X86) && OS(LINUX)) static const bool withRegisterAllocator = qgetenv("QV4_NO_REGALLOC").isEmpty(); diff --git a/src/qml/compiler/qv4isel_masm_p.h b/src/qml/compiler/qv4isel_masm_p.h index 570400656a..0c2c994e32 100644 --- a/src/qml/compiler/qv4isel_masm_p.h +++ b/src/qml/compiler/qv4isel_masm_p.h @@ -1419,7 +1419,7 @@ class Q_QML_EXPORT InstructionSelection: public EvalInstructionSelection { public: - InstructionSelection(QV4::ExecutableAllocator *execAllocator, V4IR::Module *module, QV4::Compiler::JSUnitGenerator *jsGenerator); + InstructionSelection(QQmlEnginePrivate *qmlEngine, QV4::ExecutableAllocator *execAllocator, V4IR::Module *module, QV4::Compiler::JSUnitGenerator *jsGenerator); ~InstructionSelection(); virtual void run(int functionIndex); @@ -1629,14 +1629,15 @@ private: Assembler* _as; CompilationUnit *compilationUnit; + QQmlEnginePrivate *qmlEngine; }; class Q_QML_EXPORT ISelFactory: public EvalISelFactory { public: virtual ~ISelFactory() {} - virtual EvalInstructionSelection *create(QV4::ExecutableAllocator *execAllocator, V4IR::Module *module, QV4::Compiler::JSUnitGenerator *jsGenerator) - { return new InstructionSelection(execAllocator, module, jsGenerator); } + virtual EvalInstructionSelection *create(QQmlEnginePrivate *qmlEngine, QV4::ExecutableAllocator *execAllocator, V4IR::Module *module, QV4::Compiler::JSUnitGenerator *jsGenerator) + { return new InstructionSelection(qmlEngine, execAllocator, module, jsGenerator); } virtual bool jitCompileRegexps() const { return true; } }; diff --git a/src/qml/compiler/qv4isel_moth.cpp b/src/qml/compiler/qv4isel_moth.cpp index 40ccc358f7..1b973b2359 100644 --- a/src/qml/compiler/qv4isel_moth.cpp +++ b/src/qml/compiler/qv4isel_moth.cpp @@ -152,8 +152,9 @@ inline bool isBoolType(V4IR::Expr *e) } // anonymous namespace -InstructionSelection::InstructionSelection(QV4::ExecutableAllocator *execAllocator, V4IR::Module *module, QV4::Compiler::JSUnitGenerator *jsGenerator) +InstructionSelection::InstructionSelection(QQmlEnginePrivate *qmlEngine, QV4::ExecutableAllocator *execAllocator, V4IR::Module *module, QV4::Compiler::JSUnitGenerator *jsGenerator) : EvalInstructionSelection(execAllocator, module, jsGenerator) + , qmlEngine(qmlEngine) , _block(0) , _codeStart(0) , _codeNext(0) @@ -191,7 +192,7 @@ void InstructionSelection::run(int functionIndex) qSwap(codeEnd, _codeEnd); V4IR::Optimizer opt(_function); - opt.run(); + opt.run(qmlEngine); if (opt.isInSSA()) { opt.convertOutOfSSA(); opt.showMeTheCode(_function); diff --git a/src/qml/compiler/qv4isel_moth_p.h b/src/qml/compiler/qv4isel_moth_p.h index ffb8ff4539..ef26ba875d 100644 --- a/src/qml/compiler/qv4isel_moth_p.h +++ b/src/qml/compiler/qv4isel_moth_p.h @@ -68,7 +68,7 @@ class Q_QML_EXPORT InstructionSelection: public EvalInstructionSelection { public: - InstructionSelection(QV4::ExecutableAllocator *execAllocator, V4IR::Module *module, QV4::Compiler::JSUnitGenerator *jsGenerator); + InstructionSelection(QQmlEnginePrivate *qmlEngine, QV4::ExecutableAllocator *execAllocator, V4IR::Module *module, QV4::Compiler::JSUnitGenerator *jsGenerator); ~InstructionSelection(); virtual void run(int functionIndex); @@ -168,6 +168,8 @@ private: void patchJumpAddresses(); QByteArray squeezeCode() const; + QQmlEnginePrivate *qmlEngine; + V4IR::BasicBlock *_block; V4IR::BasicBlock *_nextBlock; @@ -189,8 +191,8 @@ class Q_QML_EXPORT ISelFactory: public EvalISelFactory { public: virtual ~ISelFactory() {} - virtual EvalInstructionSelection *create(QV4::ExecutableAllocator *execAllocator, V4IR::Module *module, QV4::Compiler::JSUnitGenerator *jsGenerator) - { return new InstructionSelection(execAllocator, module, jsGenerator); } + virtual EvalInstructionSelection *create(QQmlEnginePrivate *qmlEngine, QV4::ExecutableAllocator *execAllocator, V4IR::Module *module, QV4::Compiler::JSUnitGenerator *jsGenerator) + { return new InstructionSelection(qmlEngine, execAllocator, module, jsGenerator); } virtual bool jitCompileRegexps() const { return false; } }; diff --git a/src/qml/compiler/qv4isel_p.h b/src/qml/compiler/qv4isel_p.h index 23ef7cc69e..647d85996d 100644 --- a/src/qml/compiler/qv4isel_p.h +++ b/src/qml/compiler/qv4isel_p.h @@ -52,6 +52,8 @@ QT_BEGIN_NAMESPACE +class QQmlEnginePrivate; + namespace QV4 { class ExecutableAllocator; struct Function; @@ -92,7 +94,7 @@ class Q_QML_EXPORT EvalISelFactory { public: virtual ~EvalISelFactory() = 0; - virtual EvalInstructionSelection *create(QV4::ExecutableAllocator *execAllocator, V4IR::Module *module, QV4::Compiler::JSUnitGenerator *jsGenerator) = 0; + virtual EvalInstructionSelection *create(QQmlEnginePrivate *qmlEngine, QV4::ExecutableAllocator *execAllocator, V4IR::Module *module, QV4::Compiler::JSUnitGenerator *jsGenerator) = 0; virtual bool jitCompileRegexps() const = 0; }; diff --git a/src/qml/compiler/qv4jsir.cpp b/src/qml/compiler/qv4jsir.cpp index 75261b2469..dc982e72cc 100644 --- a/src/qml/compiler/qv4jsir.cpp +++ b/src/qml/compiler/qv4jsir.cpp @@ -72,6 +72,7 @@ QString typeName(Type t) case NumberType: return QStringLiteral("number"); case StringType: return QStringLiteral("string"); case VarType: return QStringLiteral("var"); + case QObjectType: return QStringLiteral("qobject"); default: return QStringLiteral("multiple"); } } @@ -274,8 +275,16 @@ static QString dumpStart(const Expr *e) { if (e->type == UnknownType) // return QStringLiteral("**UNKNOWN**"); return QString(); - else - return typeName(e->type) + QStringLiteral("{"); + + QString result = typeName(e->type); + const Temp *temp = const_cast<Expr*>(e)->asTemp(); + if (e->type == QObjectType && temp && temp->memberResolver.data) { + result += QLatin1Char('<'); + result += QString::fromUtf8(static_cast<QQmlPropertyCache*>(temp->memberResolver.data)->className()); + result += QLatin1Char('>'); + } + result += QLatin1Char('{'); + return result; } static const char *dumpEnd(const Expr *e) { diff --git a/src/qml/compiler/qv4jsir_p.h b/src/qml/compiler/qv4jsir_p.h index 9a1bd87a1d..cb8e9d9195 100644 --- a/src/qml/compiler/qv4jsir_p.h +++ b/src/qml/compiler/qv4jsir_p.h @@ -73,6 +73,8 @@ QT_BEGIN_NAMESPACE class QTextStream; class QQmlType; class QQmlPropertyData; +class QQmlPropertyCache; +class QQmlEnginePrivate; namespace QV4 { struct ExecutionContext; @@ -181,7 +183,8 @@ enum Type { NumberType = SInt32Type | UInt32Type | DoubleType, StringType = 1 << 7, - VarType = 1 << 8 + QObjectType = 1 << 8, + VarType = 1 << 9 }; inline bool strictlyEqualTypes(Type t1, Type t2) @@ -218,6 +221,21 @@ struct StmtVisitor { virtual void visitPhi(Phi *) = 0; }; + +struct MemberExpressionResolver +{ + typedef Type (*ResolveFunction)(QQmlEnginePrivate *engine, MemberExpressionResolver *resolver, Member *member); + + MemberExpressionResolver() + : resolveMember(0), data(0) {} + + bool isValid() const { return !!resolveMember; } + void clear() { *this = MemberExpressionResolver(); } + + ResolveFunction resolveMember; + void *data; // Could be pointer to meta object, QQmlTypeNameCache, etc. - depends on resolveMember implementation +}; + struct Expr { Type type; @@ -363,6 +381,8 @@ struct Temp: Expr { unsigned scope : 28; // how many scopes outside the current one? unsigned kind : 3; unsigned isArgumentsOrEval : 1; + // Used when temp is used as base in member expression + MemberExpressionResolver memberResolver; void init(unsigned kind, unsigned index, unsigned scope) { @@ -536,7 +556,6 @@ struct Member: Expr { this->type = MemberByName; this->base = base; this->name = name; - this->memberIndex = -1; this->property = 0; } @@ -554,6 +573,7 @@ struct Member: Expr { this->type = MemberOfQObject; this->base = base; this->name = name; + this->memberIndex = -1; this->property = property; } @@ -937,6 +957,7 @@ public: Temp *newTemp = f->New<Temp>(); newTemp->init(t->kind, t->index, t->scope); newTemp->type = t->type; + newTemp->memberResolver = t->memberResolver; return newTemp; } diff --git a/src/qml/compiler/qv4regalloc.cpp b/src/qml/compiler/qv4regalloc.cpp index a6e66d2722..a0245c6808 100644 --- a/src/qml/compiler/qv4regalloc.cpp +++ b/src/qml/compiler/qv4regalloc.cpp @@ -589,6 +589,7 @@ private: Q_ASSERT(!_defs.contains(*t)); bool canHaveReg = true; switch (t->type) { + case QObjectType: case VarType: case StringType: case UndefinedType: diff --git a/src/qml/compiler/qv4ssa.cpp b/src/qml/compiler/qv4ssa.cpp index 6b1169d30a..ab2334d7dc 100644 --- a/src/qml/compiler/qv4ssa.cpp +++ b/src/qml/compiler/qv4ssa.cpp @@ -52,6 +52,7 @@ #include <qv4runtime_p.h> #include <qv4context_p.h> #include <private/qqmlpropertycache_p.h> +#include <private/qqmlengine_p.h> #include <cmath> #include <iostream> #include <cassert> @@ -1209,6 +1210,7 @@ protected: e->expr->accept(this); switch (e->expr->type) { + case QObjectType: case StringType: case VarType: markAsSideEffect(); @@ -1227,7 +1229,7 @@ protected: case OpNot: case OpIncrement: case OpDecrement: - if (e->expr->type == VarType || e->expr->type == StringType) + if (e->expr->type == VarType || e->expr->type == StringType || e->expr->type == QObjectType) markAsSideEffect(); break; @@ -1243,8 +1245,8 @@ protected: _sideEffect = checkForSideEffects(e->left); _sideEffect |= checkForSideEffects(e->right); - if (e->left->type == VarType || e->left->type == StringType - || e->right->type == VarType || e->right->type == StringType) + 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(); } @@ -1275,22 +1277,42 @@ protected: }; class TypeInference: public StmtVisitor, public ExprVisitor { + struct DiscoveredType { + int type; + MemberExpressionResolver memberResolver; + + DiscoveredType() : type(UnknownType) {} + DiscoveredType(Type t) : type(t) { Q_ASSERT(type != QObjectType); } + explicit DiscoveredType(int t) : type(t) { Q_ASSERT(type != QObjectType); } + explicit DiscoveredType(MemberExpressionResolver memberResolver) : type(QObjectType), memberResolver(memberResolver) {} + + bool test(Type t) const { return type & t; } + bool isNumber() const { return (type & NumberType) && !(type & ~NumberType); } + + bool operator!=(Type other) const { return type != other; } + bool operator==(Type other) const { return type == other; } + bool operator==(const DiscoveredType &other) const { return type == other.type; } + bool operator!=(const DiscoveredType &other) const { return type != other.type; } + }; + + QQmlEnginePrivate *qmlEngine; bool _variablesCanEscape; const DefUsesCalculator &_defUses; - QHash<Temp, int> _tempTypes; + QHash<Temp, DiscoveredType> _tempTypes; QSet<Stmt *> _worklist; struct TypingResult { - int type; + DiscoveredType type; bool fullyTyped; - TypingResult(int type, bool fullyTyped): type(type), fullyTyped(fullyTyped) {} - explicit TypingResult(int type = UnknownType): type(type), fullyTyped(type != UnknownType) {} + TypingResult(const DiscoveredType &type = DiscoveredType()) : type(type), fullyTyped(type.type != UnknownType) {} + explicit TypingResult(MemberExpressionResolver memberResolver): type(memberResolver), fullyTyped(true) {} }; TypingResult _ty; public: - TypeInference(const DefUsesCalculator &defUses) - : _defUses(defUses) + TypeInference(QQmlEnginePrivate *qmlEngine, const DefUsesCalculator &defUses) + : qmlEngine(qmlEngine) + , _defUses(defUses) , _ty(UnknownType) {} @@ -1336,7 +1358,7 @@ private: class PropagateTempTypes: public StmtVisitor, ExprVisitor { public: - PropagateTempTypes(const QHash<Temp, int> &tempTypes) + PropagateTempTypes(const QHash<Temp, DiscoveredType> &tempTypes) : _tempTypes(tempTypes) {} @@ -1352,7 +1374,11 @@ private: virtual void visitString(String *) {} virtual void visitRegExp(RegExp *) {} virtual void visitName(Name *) {} - virtual void visitTemp(Temp *e) { e->type = (Type) _tempTypes[*e]; } + virtual void visitTemp(Temp *e) { + DiscoveredType t = _tempTypes[*e]; + e->type = (Type) t.type; + e->memberResolver = t.memberResolver; + } virtual void visitClosure(Closure *) {} virtual void visitConvert(Convert *e) { e->expr->accept(this); } virtual void visitUnop(Unop *e) { e->expr->accept(this); } @@ -1393,7 +1419,7 @@ private: } private: - QHash<Temp, int> _tempTypes; + QHash<Temp, DiscoveredType> _tempTypes; }; private: @@ -1429,13 +1455,13 @@ private: } } - void setType(Expr *e, int ty) { + void setType(Expr *e, DiscoveredType ty) { if (Temp *t = e->asTemp()) { #if defined(SHOW_SSA) qout<<"Setting type for "<< (t->scope?"scoped temp ":"temp ") <<t->index<< " to "<<typeName(Type(ty)) << " (" << ty << ")" << endl; #endif if (isAlwaysAnObject(t)) - ty = VarType; + ty = DiscoveredType(VarType); if (_tempTypes[*t] != ty) { _tempTypes[*t] = ty; @@ -1450,7 +1476,7 @@ private: _worklist += QSet<Stmt *>::fromList(_defUses.uses(*t)); } } else { - e->type = (Type) ty; + e->type = (Type) ty.type; } } @@ -1472,8 +1498,10 @@ protected: virtual void visitTemp(Temp *e) { if (isAlwaysAnObject(e)) _ty = TypingResult(VarType); + else if (e->memberResolver.isValid()) + _ty = TypingResult(e->memberResolver); else - _ty = TypingResult(_tempTypes.value(*e, UnknownType)); + _ty = TypingResult(_tempTypes.value(*e)); setType(e, _ty.type); } virtual void visitClosure(Closure *) { _ty = TypingResult(VarType); } @@ -1505,9 +1533,9 @@ protected: switch (e->op) { case OpAdd: - if (leftTy.type & VarType || rightTy.type & VarType) + if (leftTy.type.test(VarType) || leftTy.type.test(QObjectType) || rightTy.type.test(VarType) || rightTy.type.test(QObjectType)) _ty.type = VarType; - else if (leftTy.type & StringType || rightTy.type & StringType) + else if (leftTy.type.test(StringType) || rightTy.type.test(StringType)) _ty.type = StringType; else if (leftTy.type != UnknownType && rightTy.type != UnknownType) _ty.type = DoubleType; @@ -1574,14 +1602,13 @@ protected: } virtual void visitMember(Member *e) { - if (e->type == Member::MemberOfQObject - && !e->property->isEnum() // Enums need to go through run-time getters/setters to ensure correct string handling. - ) { - _ty = TypingResult(irTypeFromPropertyType(e->property->propType)); - return; - } _ty = run(e->base); - _ty.type = VarType; + + if (_ty.fullyTyped && _ty.type.memberResolver.isValid()) { + MemberExpressionResolver &resolver = _ty.type.memberResolver; + _ty.type.type = resolver.resolveMember(qmlEngine, &resolver, e); + } else + _ty.type = VarType; } virtual void visitExp(Exp *s) { _ty = run(s->expr); } @@ -1611,11 +1638,13 @@ protected: _ty.fullyTyped = false; break; } - _ty.type |= ty.type; + _ty.type.type |= ty.type.type; _ty.fullyTyped &= ty.fullyTyped; + if (_ty.type.test(QObjectType)) + _ty.type.memberResolver.clear(); // ### TODO: find common ancestor meta-object } - switch (_ty.type) { + switch (_ty.type.type) { case UnknownType: case UndefinedType: case NullType: @@ -1624,13 +1653,14 @@ protected: case UInt32Type: case DoubleType: case StringType: + case QObjectType: case VarType: // The type is not a combination of two or more types, so we're done. break; default: // There are multiple types involved, so: - if ((_ty.type & NumberType) && !(_ty.type & ~NumberType)) + if (_ty.type.isNumber()) // The type is any combination of double/int32/uint32, but nothing else. So we can // type it as double. _ty.type = DoubleType; @@ -1641,18 +1671,6 @@ protected: setType(s->targetTemp, _ty.type); } - - static int irTypeFromPropertyType(int propType) - { - switch (propType) { - case QMetaType::Bool: return BoolType; - case QMetaType::Int: return SInt32Type; - case QMetaType::Double: return DoubleType; - case QMetaType::QString: return StringType; - default: break; - } - return VarType; - } }; void convertConst(Const *c, Type targetType) @@ -2356,10 +2374,10 @@ bool tryOptimizingComparison(Expr *&expr) if (!b) return false; Const *leftConst = b->left->asConst(); - if (!leftConst || leftConst->type == StringType || leftConst->type == VarType) + if (!leftConst || leftConst->type == StringType || leftConst->type == VarType || leftConst->type == QObjectType) return false; Const *rightConst = b->right->asConst(); - if (!rightConst || rightConst->type == StringType || rightConst->type == VarType) + if (!rightConst || rightConst->type == StringType || rightConst->type == VarType || rightConst->type == QObjectType) return false; QV4::Primitive l = convertToValue(leftConst); @@ -2570,10 +2588,10 @@ void optimizeSSA(Function *function, DefUsesCalculator &defUses) // TODO: If the result of the move is only used in one single cjump, then // inline the binop into the cjump. Const *leftConst = binop->left->asConst(); - if (!leftConst || leftConst->type == StringType || leftConst->type == VarType) + if (!leftConst || leftConst->type == StringType || leftConst->type == VarType || leftConst->type == QObjectType) continue; Const *rightConst = binop->right->asConst(); - if (!rightConst || rightConst->type == StringType || rightConst->type == VarType) + if (!rightConst || rightConst->type == StringType || rightConst->type == VarType || rightConst->type == QObjectType) continue; QV4::Primitive lc = convertToValue(leftConst); @@ -2957,7 +2975,7 @@ bool LifeTimeInterval::lessThanForTemp(const LifeTimeInterval &r1, const LifeTim return r1.temp() < r2.temp(); } -void Optimizer::run() +void Optimizer::run(QQmlEnginePrivate *qmlEngine) { #if defined(SHOW_SSA) qout << "##### NOW IN FUNCTION " << (function->name ? qPrintable(*function->name) : "anonymous!") @@ -2999,7 +3017,7 @@ void Optimizer::run() // showMeTheCode(function); // qout << "Running type inference..." << endl; - TypeInference(defUses).run(function); + TypeInference(qmlEngine, defUses).run(function); // showMeTheCode(function); // qout << "Doing type propagation..." << endl; diff --git a/src/qml/compiler/qv4ssa_p.h b/src/qml/compiler/qv4ssa_p.h index aa713d3fec..dcbc83ae65 100644 --- a/src/qml/compiler/qv4ssa_p.h +++ b/src/qml/compiler/qv4ssa_p.h @@ -46,6 +46,7 @@ QT_BEGIN_NAMESPACE class QTextStream; +class QQmlEnginePrivate; namespace QQmlJS { namespace V4IR { @@ -129,7 +130,7 @@ public: , inSSA(false) {} - void run(); + void run(QQmlEnginePrivate *qmlEngine); void convertOutOfSSA(); bool isInSSA() const diff --git a/src/qml/jsruntime/qv4functionobject.cpp b/src/qml/jsruntime/qv4functionobject.cpp index 99797ec56b..037f06cd35 100644 --- a/src/qml/jsruntime/qv4functionobject.cpp +++ b/src/qml/jsruntime/qv4functionobject.cpp @@ -55,6 +55,7 @@ #include <private/qqmljsparser_p.h> #include <private/qqmljsast_p.h> #include <private/qqmlcontextwrapper_p.h> +#include <private/qqmlengine_p.h> #include <qv4jsir_p.h> #include <qv4codegen_p.h> #include "private/qlocale_tools_p.h" @@ -281,7 +282,7 @@ ReturnedValue FunctionCtor::construct(Managed *that, CallData *callData) cg.generateFromFunctionExpression(QString(), function, fe, &module); QV4::Compiler::JSUnitGenerator jsGenerator(&module); - QScopedPointer<QQmlJS::EvalInstructionSelection> isel(v4->iselFactory->create(v4->executableAllocator, &module, &jsGenerator)); + QScopedPointer<QQmlJS::EvalInstructionSelection> isel(v4->iselFactory->create(QQmlEnginePrivate::get(v4), v4->executableAllocator, &module, &jsGenerator)); QV4::CompiledData::CompilationUnit *compilationUnit = isel->compile(); QV4::Function *vmf = compilationUnit->linkToEngine(v4); diff --git a/src/qml/jsruntime/qv4script.cpp b/src/qml/jsruntime/qv4script.cpp index 2f015ac83a..c65f1baf2b 100644 --- a/src/qml/jsruntime/qv4script.cpp +++ b/src/qml/jsruntime/qv4script.cpp @@ -51,6 +51,7 @@ #include <private/qqmljslexer_p.h> #include <private/qqmljsparser_p.h> #include <private/qqmljsast_p.h> +#include <private/qqmlengine_p.h> #include <qv4jsir_p.h> #include <qv4codegen_p.h> @@ -229,7 +230,7 @@ void Script::parse() return; QV4::Compiler::JSUnitGenerator jsGenerator(&module); - QScopedPointer<EvalInstructionSelection> isel(v4->iselFactory->create(v4->executableAllocator, &module, &jsGenerator)); + QScopedPointer<EvalInstructionSelection> isel(v4->iselFactory->create(QQmlEnginePrivate::get(v4), v4->executableAllocator, &module, &jsGenerator)); if (inheritContext) isel->setUseFastLookups(false); QV4::CompiledData::CompilationUnit *compilationUnit = isel->compile(); @@ -355,7 +356,7 @@ CompiledData::CompilationUnit *Script::precompile(ExecutionEngine *engine, const } Compiler::JSUnitGenerator jsGenerator(&module); - QScopedPointer<QQmlJS::EvalInstructionSelection> isel(engine->iselFactory->create(engine->executableAllocator, &module, &jsGenerator)); + QScopedPointer<QQmlJS::EvalInstructionSelection> isel(engine->iselFactory->create(QQmlEnginePrivate::get(engine), engine->executableAllocator, &module, &jsGenerator)); isel->setUseFastLookups(false); return isel->compile(); } diff --git a/src/qml/qml/qqmlcompiler.cpp b/src/qml/qml/qqmlcompiler.cpp index 7b33849e67..79fc3ba303 100644 --- a/src/qml/qml/qqmlcompiler.cpp +++ b/src/qml/qml/qqmlcompiler.cpp @@ -919,7 +919,7 @@ void QQmlCompiler::compileTree(QQmlScript::Object *tree) if (!jsModule->functions.isEmpty()) { QV4::ExecutionEngine *v4 = QV8Engine::getV4(engine); QV4::Compiler::JSUnitGenerator jsUnitGenerator(jsModule.data()); - QScopedPointer<QQmlJS::EvalInstructionSelection> isel(v4->iselFactory->create(v4->executableAllocator, jsModule.data(), &jsUnitGenerator)); + QScopedPointer<QQmlJS::EvalInstructionSelection> isel(v4->iselFactory->create(enginePrivate, v4->executableAllocator, jsModule.data(), &jsUnitGenerator)); isel->setUseFastLookups(false); QV4::CompiledData::CompilationUnit *jsUnit = isel->compile(/*generated unit data*/true); output->compilationUnit = jsUnit; diff --git a/src/qml/qml/qqmlengine_p.h b/src/qml/qml/qqmlengine_p.h index 22ca8b8057..19eb320fbe 100644 --- a/src/qml/qml/qqmlengine_p.h +++ b/src/qml/qml/qqmlengine_p.h @@ -257,6 +257,7 @@ public: inline static QQmlEnginePrivate *get(QQmlContext *c); inline static QQmlEnginePrivate *get(QQmlContextData *c); inline static QQmlEngine *get(QQmlEnginePrivate *p); + inline static QQmlEnginePrivate *get(QV4::ExecutionEngine *e); static void registerBaseTypes(const char *uri, int versionMajor, int versionMinor); static void registerQtQuick2Types(const char *uri, int versionMajor, int versionMinor); @@ -516,7 +517,17 @@ QQmlEngine *QQmlEnginePrivate::get(QQmlEnginePrivate *p) { Q_ASSERT(p); - return p->q_func(); + return p->q_func(); +} + +QQmlEnginePrivate *QQmlEnginePrivate::get(QV4::ExecutionEngine *e) +{ + if (!e->v8Engine) + return 0; + QQmlEngine *qmlEngine = e->v8Engine->engine(); + if (!qmlEngine) + return 0; + return get(qmlEngine); } void QQmlEnginePrivate::captureProperty(QQmlNotifier *n) diff --git a/src/qml/qml/qqmltypeloader.cpp b/src/qml/qml/qqmltypeloader.cpp index 895a2a9cd6..911761d9fd 100644 --- a/src/qml/qml/qqmltypeloader.cpp +++ b/src/qml/qml/qqmltypeloader.cpp @@ -2377,7 +2377,7 @@ void QQmlTypeData::compile() QV4::ExecutionEngine *v4 = QV8Engine::getV4(m_typeLoader->engine()); - QScopedPointer<QQmlJS::EvalInstructionSelection> isel(v4->iselFactory->create(v4->executableAllocator, &parsedQML->jsModule, &parsedQML->jsGenerator)); + QScopedPointer<QQmlJS::EvalInstructionSelection> isel(v4->iselFactory->create(enginePrivate, v4->executableAllocator, &parsedQML->jsModule, &parsedQML->jsGenerator)); isel->setUseFastLookups(false); QV4::CompiledData::CompilationUnit *jsUnit = isel->compile(/*generated unit data*/false); |