aboutsummaryrefslogtreecommitdiffstats
path: root/src/qml/compiler
diff options
context:
space:
mode:
authorSimon Hausmann <simon.hausmann@digia.com>2013-11-02 22:46:25 +0100
committerThe Qt Project <gerrit-noreply@qt-project.org>2013-11-25 22:04:42 +0100
commit43f1cc98bf1899ae29e3fb0b3bf5054d5a23d4b2 (patch)
tree1d0912be4c0daf35e4255259f51e4a3c11b9f004 /src/qml/compiler
parenta41764cafbc85c271edde8d09eae46798ccdcb8d (diff)
Initial support for accelerated property access to QML singletons and enums
With this patch we determine the meta-object of singletons, propagate it into the IR and load them separately using a dedicated run-time function. In addition enums in singletons and QML types are resolved at compile time. Change-Id: I01ce1288391b476d1c9af669cb2987a44c885703 Reviewed-by: Lars Knoll <lars.knoll@digia.com>
Diffstat (limited to 'src/qml/compiler')
-rw-r--r--src/qml/compiler/qqmlcodegenerator.cpp78
-rw-r--r--src/qml/compiler/qv4instr_moth_p.h9
-rw-r--r--src/qml/compiler/qv4isel_masm.cpp5
-rw-r--r--src/qml/compiler/qv4isel_masm_p.h1
-rw-r--r--src/qml/compiler/qv4isel_moth.cpp8
-rw-r--r--src/qml/compiler/qv4isel_moth_p.h1
-rw-r--r--src/qml/compiler/qv4isel_p.cpp2
-rw-r--r--src/qml/compiler/qv4isel_p.h1
-rw-r--r--src/qml/compiler/qv4jsir.cpp6
-rw-r--r--src/qml/compiler/qv4jsir_p.h21
-rw-r--r--src/qml/compiler/qv4regalloc.cpp8
-rw-r--r--src/qml/compiler/qv4ssa.cpp13
12 files changed, 138 insertions, 15 deletions
diff --git a/src/qml/compiler/qqmlcodegenerator.cpp b/src/qml/compiler/qqmlcodegenerator.cpp
index b38e2670e6..dcfad00472 100644
--- a/src/qml/compiler/qqmlcodegenerator.cpp
+++ b/src/qml/compiler/qqmlcodegenerator.cpp
@@ -1319,20 +1319,43 @@ static QQmlPropertyData *lookupQmlCompliantProperty(QQmlPropertyCache *cache, co
static void initMetaObjectResolver(V4IR::MemberExpressionResolver *resolver, QQmlPropertyCache *metaObject);
+enum MetaObjectResolverFlags {
+ AllPropertiesAreFinal = 0x1,
+ LookupsIncludeEnums = 0x2,
+ LookupsExcludeProperties = 0x4
+};
+
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;
+ QQmlPropertyCache *metaObject = static_cast<QQmlPropertyCache*>(resolver->data);
+
+ if (member->name->constData()->isUpper() && (resolver->flags & LookupsIncludeEnums)) {
+ const QMetaObject *mo = metaObject->createMetaObject();
+ QByteArray enumName = member->name->toUtf8();
+ for (int ii = mo->enumeratorCount() - 1; ii >= 0; --ii) {
+ QMetaEnum metaEnum = mo->enumerator(ii);
+ bool ok;
+ int value = metaEnum.keyToValue(enumName.constData(), &ok);
+ if (ok) {
+ member->memberIsEnum = true;
+ member->enumValue = value;
+ resolver->clear();
+ return V4IR::SInt32Type;
+ }
+ }
+ }
+ if (qmlEngine && !(resolver->flags & LookupsExcludeProperties)) {
+ 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 (QQmlPropertyData *candidate = metaObject->property(*member->name, /*object*/0, /*context*/0)) {
+ const bool isFinalProperty = (candidate->isFinal() || (resolver->flags & AllPropertiesAreFinal))
+ && !candidate->isFunction();
+ if (isFinalProperty && metaObject->isAllowedInRevision(candidate)) {
+ property = candidate;
+ member->property = candidate; // Cache for next iteration and isel needs it.
+ }
}
}
@@ -1366,6 +1389,7 @@ static void initMetaObjectResolver(V4IR::MemberExpressionResolver *resolver, QQm
{
resolver->resolveMember = &resolveMetaObjectProperty;
resolver->data = metaObject;
+ resolver->flags = 0;
}
void JSCodeGen::beginFunctionBodyHook()
@@ -1418,10 +1442,40 @@ V4IR::Expr *JSCodeGen::fallbackNameLookup(const QString &name, int line, int col
{
QQmlTypeNameCache::Result r = imports->query(name);
if (r.isValid()) {
- if (r.scriptIndex != -1)
- return subscript(_block->TEMP(_importedScriptsTemp), _block->CONST(V4IR::NumberType, r.scriptIndex));
- else
+ if (r.scriptIndex != -1) {
+ return subscript(_block->TEMP(_importedScriptsTemp), _block->CONST(V4IR::SInt32Type, r.scriptIndex));
+ } else if (r.type) {
+ V4IR::Name *typeName = _block->NAME(name, line, col);
+ V4IR::Temp *result = _block->TEMP(_block->newTemp());
+
+ if (r.type->isSingleton()) {
+ if (r.type->isCompositeSingleton()) {
+ QQmlTypeData *tdata = engine->typeLoader.getType(r.type->singletonInstanceInfo()->url);
+ Q_ASSERT(tdata);
+ Q_ASSERT(tdata->isComplete());
+ initMetaObjectResolver(&result->memberResolver, engine->propertyCacheForType(tdata->compiledData()->metaTypeId));
+ result->memberResolver.flags |= AllPropertiesAreFinal;
+ } else {
+ const QMetaObject *singletonMo = r.type->singletonInstanceInfo()->instanceMetaObject;
+ if (!singletonMo) // We can only accelerate C++ singletons that were registered with their meta-type
+ return 0;
+ initMetaObjectResolver(&result->memberResolver, engine->cache(singletonMo));
+ }
+
+ // Instruct the isel to not load this as activation property but through the
+ // run-time's singleton getter.
+ typeName->qmlSingleton = true;
+ } else {
+ initMetaObjectResolver(&result->memberResolver,engine->cache(r.type->metaObject()));
+ result->memberResolver.flags |= LookupsExcludeProperties;
+ }
+ typeName->freeOfSideEffects = true;
+ result->memberResolver.flags |= LookupsIncludeEnums;
+ _block->MOVE(result, typeName);
+ return _block->TEMP(result->index);
+ } else {
return 0; // TODO: We can't do fast lookup for these yet.
+ }
}
}
diff --git a/src/qml/compiler/qv4instr_moth_p.h b/src/qml/compiler/qv4instr_moth_p.h
index 5c92439f0c..180391ff33 100644
--- a/src/qml/compiler/qv4instr_moth_p.h
+++ b/src/qml/compiler/qv4instr_moth_p.h
@@ -129,7 +129,8 @@ QT_BEGIN_NAMESPACE
F(LoadQmlIdArray, loadQmlIdArray) \
F(LoadQmlImportedScripts, loadQmlImportedScripts) \
F(LoadQmlContextObject, loadQmlContextObject) \
- F(LoadQmlScopeObject, loadQmlScopeObject)
+ F(LoadQmlScopeObject, loadQmlScopeObject) \
+ F(LoadQmlSingleton, loadQmlSingleton)
#if defined(Q_CC_GNU) && (!defined(Q_CC_INTEL) || __INTEL_COMPILER >= 1200)
# define MOTH_THREADED_INTERPRETER
@@ -670,6 +671,11 @@ union Instr
MOTH_INSTR_HEADER
Param result;
};
+ struct instr_loadQmlSingleton {
+ MOTH_INSTR_HEADER
+ Param result;
+ int name;
+ };
instr_common common;
instr_ret ret;
@@ -752,6 +758,7 @@ union Instr
instr_loadQmlImportedScripts loadQmlImportedScripts;
instr_loadQmlContextObject loadQmlContextObject;
instr_loadQmlScopeObject loadQmlScopeObject;
+ instr_loadQmlSingleton loadQmlSingleton;
static int size(Type type);
};
diff --git a/src/qml/compiler/qv4isel_masm.cpp b/src/qml/compiler/qv4isel_masm.cpp
index 0854dd55ab..468fef4116 100644
--- a/src/qml/compiler/qv4isel_masm.cpp
+++ b/src/qml/compiler/qv4isel_masm.cpp
@@ -900,6 +900,11 @@ void InstructionSelection::loadQmlScopeObject(V4IR::Temp *temp)
generateFunctionCall(temp, __qmljs_get_scope_object, Assembler::ContextRegister);
}
+void InstructionSelection::loadQmlSingleton(const QString &name, V4IR::Temp *temp)
+{
+ generateFunctionCall(temp, __qmljs_get_qml_singleton, Assembler::ContextRegister, Assembler::PointerToString(name));
+}
+
void InstructionSelection::loadConst(V4IR::Const *sourceConst, V4IR::Temp *targetTemp)
{
if (targetTemp->kind == V4IR::Temp::PhysicalRegister) {
diff --git a/src/qml/compiler/qv4isel_masm_p.h b/src/qml/compiler/qv4isel_masm_p.h
index 5a02b62a73..4b0d19df07 100644
--- a/src/qml/compiler/qv4isel_masm_p.h
+++ b/src/qml/compiler/qv4isel_masm_p.h
@@ -1461,6 +1461,7 @@ protected:
virtual void loadQmlImportedScripts(V4IR::Temp *temp);
virtual void loadQmlContextObject(V4IR::Temp *temp);
virtual void loadQmlScopeObject(V4IR::Temp *temp);
+ virtual void loadQmlSingleton(const QString &name, V4IR::Temp *temp);
virtual void loadConst(V4IR::Const *sourceConst, V4IR::Temp *targetTemp);
virtual void loadString(const QString &str, V4IR::Temp *targetTemp);
virtual void loadRegexp(V4IR::RegExp *sourceRegexp, V4IR::Temp *targetTemp);
diff --git a/src/qml/compiler/qv4isel_moth.cpp b/src/qml/compiler/qv4isel_moth.cpp
index c76c236de4..ee7e8ce2e8 100644
--- a/src/qml/compiler/qv4isel_moth.cpp
+++ b/src/qml/compiler/qv4isel_moth.cpp
@@ -416,6 +416,14 @@ void InstructionSelection::loadQmlScopeObject(V4IR::Temp *temp)
addInstruction(load);
}
+void InstructionSelection::loadQmlSingleton(const QString &name, V4IR::Temp *temp)
+{
+ Instruction::LoadQmlSingleton load;
+ load.result = getResultParam(temp);
+ load.name = registerString(name);
+ addInstruction(load);
+}
+
void InstructionSelection::loadConst(V4IR::Const *sourceConst, V4IR::Temp *targetTemp)
{
assert(sourceConst);
diff --git a/src/qml/compiler/qv4isel_moth_p.h b/src/qml/compiler/qv4isel_moth_p.h
index bde7997c33..031c2d838a 100644
--- a/src/qml/compiler/qv4isel_moth_p.h
+++ b/src/qml/compiler/qv4isel_moth_p.h
@@ -116,6 +116,7 @@ protected:
virtual void loadQmlImportedScripts(V4IR::Temp *temp);
virtual void loadQmlContextObject(V4IR::Temp *temp);
virtual void loadQmlScopeObject(V4IR::Temp *temp);
+ virtual void loadQmlSingleton(const QString &name, V4IR::Temp *temp);
virtual void loadConst(V4IR::Const *sourceConst, V4IR::Temp *targetTemp);
virtual void loadString(const QString &str, V4IR::Temp *targetTemp);
virtual void loadRegexp(V4IR::RegExp *sourceRegexp, V4IR::Temp *targetTemp);
diff --git a/src/qml/compiler/qv4isel_p.cpp b/src/qml/compiler/qv4isel_p.cpp
index a14a11c43e..96a3370903 100644
--- a/src/qml/compiler/qv4isel_p.cpp
+++ b/src/qml/compiler/qv4isel_p.cpp
@@ -111,6 +111,8 @@ void IRDecoder::visitMove(V4IR::Move *s)
loadQmlScopeObject(t);
else if (n->builtin == V4IR::Name::builtin_qml_imported_scripts_object)
loadQmlImportedScripts(t);
+ else if (n->qmlSingleton)
+ loadQmlSingleton(*n->id, t);
else
getActivationProperty(n, t);
return;
diff --git a/src/qml/compiler/qv4isel_p.h b/src/qml/compiler/qv4isel_p.h
index 6671ac1426..7ee5cbba4e 100644
--- a/src/qml/compiler/qv4isel_p.h
+++ b/src/qml/compiler/qv4isel_p.h
@@ -148,6 +148,7 @@ public: // to implement by subclasses:
virtual void loadQmlImportedScripts(V4IR::Temp *temp) = 0;
virtual void loadQmlContextObject(V4IR::Temp *temp) = 0;
virtual void loadQmlScopeObject(V4IR::Temp *temp) = 0;
+ virtual void loadQmlSingleton(const QString &name, V4IR::Temp *temp) = 0;
virtual void loadConst(V4IR::Const *sourceConst, V4IR::Temp *targetTemp) = 0;
virtual void loadString(const QString &str, V4IR::Temp *targetTemp) = 0;
virtual void loadRegexp(V4IR::RegExp *sourceRegexp, V4IR::Temp *targetTemp) = 0;
diff --git a/src/qml/compiler/qv4jsir.cpp b/src/qml/compiler/qv4jsir.cpp
index 79b963f400..41502dbd4f 100644
--- a/src/qml/compiler/qv4jsir.cpp
+++ b/src/qml/compiler/qv4jsir.cpp
@@ -372,6 +372,8 @@ void Name::initGlobal(const QString *id, quint32 line, quint32 column)
this->id = id;
this->builtin = builtin_invalid;
this->global = true;
+ this->qmlSingleton = false;
+ this->freeOfSideEffects = false;
this->line = line;
this->column = column;
}
@@ -381,6 +383,8 @@ void Name::init(const QString *id, quint32 line, quint32 column)
this->id = id;
this->builtin = builtin_invalid;
this->global = false;
+ this->qmlSingleton = false;
+ this->freeOfSideEffects = false;
this->line = line;
this->column = column;
}
@@ -390,6 +394,8 @@ void Name::init(Builtin builtin, quint32 line, quint32 column)
this->id = 0;
this->builtin = builtin;
this->global = false;
+ this->qmlSingleton = false;
+ this->freeOfSideEffects = false;
this->line = line;
this->column = column;
}
diff --git a/src/qml/compiler/qv4jsir_p.h b/src/qml/compiler/qv4jsir_p.h
index fd54460b5c..aa85c4cf3c 100644
--- a/src/qml/compiler/qv4jsir_p.h
+++ b/src/qml/compiler/qv4jsir_p.h
@@ -55,6 +55,7 @@
#include "private/qv4global_p.h"
#include <private/qqmljsmemorypool_p.h>
#include <private/qqmljsastfwd_p.h>
+#include <private/qflagpointer_p.h>
#include <QtCore/QVector>
#include <QtCore/QString>
@@ -124,6 +125,14 @@ struct CJump;
struct Ret;
struct Phi;
+// Flag pointer:
+// * The first flag indicates whether the meta object is final.
+// If final, then none of its properties themselves need to
+// be final when considering for lookups in QML.
+// * The second flag indicates whether enums should be included
+// in the lookup of properties or not. The default is false.
+typedef QFlagPointer<QQmlPropertyCache> IRMetaObject;
+
enum AluOp {
OpInvalid = 0,
@@ -227,13 +236,14 @@ struct MemberExpressionResolver
typedef Type (*ResolveFunction)(QQmlEnginePrivate *engine, MemberExpressionResolver *resolver, Member *member);
MemberExpressionResolver()
- : resolveMember(0), data(0) {}
+ : resolveMember(0), data(0), flags(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
+ int flags;
};
struct Expr {
@@ -351,7 +361,9 @@ struct Name: Expr {
const QString *id;
Builtin builtin;
- bool global;
+ bool global : 1;
+ bool qmlSingleton : 1;
+ bool freeOfSideEffects : 1;
quint32 line;
quint32 column;
@@ -543,12 +555,15 @@ struct Member: Expr {
Expr *base;
const QString *name;
QQmlPropertyData *property;
+ int enumValue;
+ bool memberIsEnum;
void init(Expr *base, const QString *name, QQmlPropertyData *property = 0)
{
this->base = base;
this->name = name;
this->property = property;
+ this->memberIsEnum = false;
}
virtual void accept(ExprVisitor *v) { v->visitMember(this); }
@@ -919,6 +934,8 @@ public:
newName->id = n->id;
newName->builtin = n->builtin;
newName->global = n->global;
+ newName->qmlSingleton = n->qmlSingleton;
+ newName->freeOfSideEffects = n->freeOfSideEffects;
newName->line = n->line;
newName->column = n->column;
return newName;
diff --git a/src/qml/compiler/qv4regalloc.cpp b/src/qml/compiler/qv4regalloc.cpp
index a1594da82e..5d1dc14500 100644
--- a/src/qml/compiler/qv4regalloc.cpp
+++ b/src/qml/compiler/qv4regalloc.cpp
@@ -364,6 +364,14 @@ protected: // IRDecoder
addCall();
}
+ virtual void loadQmlSingleton(const QString &/*name*/, Temp *temp)
+ {
+ Q_UNUSED(temp);
+
+ addDef(temp);
+ addCall();
+ }
+
virtual void loadConst(V4IR::Const *sourceConst, V4IR::Temp *targetTemp)
{
Q_UNUSED(sourceConst);
diff --git a/src/qml/compiler/qv4ssa.cpp b/src/qml/compiler/qv4ssa.cpp
index 1f6ace359c..f9acf99a65 100644
--- a/src/qml/compiler/qv4ssa.cpp
+++ b/src/qml/compiler/qv4ssa.cpp
@@ -1189,6 +1189,8 @@ protected:
virtual void visitName(Name *e)
{
+ if (e->freeOfSideEffects)
+ return;
// TODO: maybe we can distinguish between built-ins of which we know that they do not have
// a side-effect.
if (e->builtin == Name::builtin_invalid || (e->id && *e->id != QStringLiteral("this")))
@@ -2512,6 +2514,17 @@ void optimizeSSA(Function *function, DefUsesCalculator &defUses)
}
continue;
}
+ if (Member *potentialEnumMember = m->source->asMember()) {
+ if (potentialEnumMember->memberIsEnum) {
+ Const *c = function->New<Const>();
+ c->init(SInt32Type, potentialEnumMember->enumValue);
+ W += replaceUses(targetTemp, c);
+ defUses.removeDef(*targetTemp);
+ *ref[s] = 0;
+ defUses.removeUse(s, *potentialEnumMember->base->asTemp());
+ continue;
+ }
+ }
// copy propagation:
if (Temp *sourceTemp = unescapableTemp(m->source, variablesCanEscape)) {