aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--src/qml/compiler/qqmlcodegenerator.cpp93
-rw-r--r--src/qml/compiler/qqmlcodegenerator_p.h3
-rw-r--r--src/qml/compiler/qv4codegen_p.h2
-rw-r--r--src/qml/compiler/qv4isel_masm.cpp5
-rw-r--r--src/qml/compiler/qv4isel_masm_p.h7
-rw-r--r--src/qml/compiler/qv4isel_moth.cpp5
-rw-r--r--src/qml/compiler/qv4isel_moth_p.h8
-rw-r--r--src/qml/compiler/qv4isel_p.h4
-rw-r--r--src/qml/compiler/qv4jsir.cpp13
-rw-r--r--src/qml/compiler/qv4jsir_p.h25
-rw-r--r--src/qml/compiler/qv4regalloc.cpp1
-rw-r--r--src/qml/compiler/qv4ssa.cpp110
-rw-r--r--src/qml/compiler/qv4ssa_p.h3
-rw-r--r--src/qml/jsruntime/qv4functionobject.cpp3
-rw-r--r--src/qml/jsruntime/qv4script.cpp5
-rw-r--r--src/qml/qml/qqmlcompiler.cpp2
-rw-r--r--src/qml/qml/qqmlengine_p.h13
-rw-r--r--src/qml/qml/qqmltypeloader.cpp2
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);