diff options
-rw-r--r-- | src/qml/compiler/qqmlcodegenerator.cpp | 78 | ||||
-rw-r--r-- | src/qml/compiler/qv4instr_moth_p.h | 9 | ||||
-rw-r--r-- | src/qml/compiler/qv4isel_masm.cpp | 5 | ||||
-rw-r--r-- | src/qml/compiler/qv4isel_masm_p.h | 1 | ||||
-rw-r--r-- | src/qml/compiler/qv4isel_moth.cpp | 8 | ||||
-rw-r--r-- | src/qml/compiler/qv4isel_moth_p.h | 1 | ||||
-rw-r--r-- | src/qml/compiler/qv4isel_p.cpp | 2 | ||||
-rw-r--r-- | src/qml/compiler/qv4isel_p.h | 1 | ||||
-rw-r--r-- | src/qml/compiler/qv4jsir.cpp | 6 | ||||
-rw-r--r-- | src/qml/compiler/qv4jsir_p.h | 21 | ||||
-rw-r--r-- | src/qml/compiler/qv4regalloc.cpp | 8 | ||||
-rw-r--r-- | src/qml/compiler/qv4ssa.cpp | 13 | ||||
-rw-r--r-- | src/qml/jsruntime/qv4runtime.cpp | 5 | ||||
-rw-r--r-- | src/qml/jsruntime/qv4runtime_p.h | 1 | ||||
-rw-r--r-- | src/qml/jsruntime/qv4vme_moth.cpp | 4 | ||||
-rw-r--r-- | src/qml/qml/qqmlcontextwrapper.cpp | 19 | ||||
-rw-r--r-- | src/qml/qml/qqmlcontextwrapper_p.h | 1 | ||||
-rw-r--r-- | src/qml/qml/qqmlmetatype.cpp | 8 |
18 files changed, 174 insertions, 17 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)) { diff --git a/src/qml/jsruntime/qv4runtime.cpp b/src/qml/jsruntime/qv4runtime.cpp index fbd4496875..a5a93e1f84 100644 --- a/src/qml/jsruntime/qv4runtime.cpp +++ b/src/qml/jsruntime/qv4runtime.cpp @@ -1288,6 +1288,11 @@ ReturnedValue __qmljs_get_imported_scripts(NoThrowContext *ctx) return context->importedScripts.value(); } +QV4::ReturnedValue __qmljs_get_qml_singleton(QV4::NoThrowContext *ctx, const QV4::StringRef name) +{ + return ctx->engine->qmlContextObject()->getPointer()->as<QmlContextWrapper>()->qmlSingletonWrapper(name); +} + void __qmljs_builtin_convert_this_to_object(ExecutionContext *ctx) { SafeValue *t = &ctx->callData->thisObject; diff --git a/src/qml/jsruntime/qv4runtime_p.h b/src/qml/jsruntime/qv4runtime_p.h index 935ccd2012..da596b180c 100644 --- a/src/qml/jsruntime/qv4runtime_p.h +++ b/src/qml/jsruntime/qv4runtime_p.h @@ -177,6 +177,7 @@ QV4::ReturnedValue __qmljs_get_context_object(NoThrowContext *ctx); QV4::ReturnedValue __qmljs_get_scope_object(NoThrowContext *ctx); QV4::ReturnedValue __qmljs_get_qobject_property(ExecutionContext *ctx, const ValueRef object, int propertyIndex, bool captureRequired); void __qmljs_set_qobject_property(ExecutionContext *ctx, const ValueRef object, int propertyIndex, const ValueRef value); +QV4::ReturnedValue __qmljs_get_qml_singleton(NoThrowContext *ctx, const QV4::StringRef name); // For each QV4::ReturnedValue __qmljs_foreach_iterator_object(QV4::ExecutionContext *ctx, const QV4::ValueRef in); diff --git a/src/qml/jsruntime/qv4vme_moth.cpp b/src/qml/jsruntime/qv4vme_moth.cpp index 944fe6e514..00672fea0f 100644 --- a/src/qml/jsruntime/qv4vme_moth.cpp +++ b/src/qml/jsruntime/qv4vme_moth.cpp @@ -673,6 +673,10 @@ QV4::ReturnedValue VME::run(QV4::ExecutionContext *context, const uchar *code, VALUE(instr.result) = __qmljs_get_scope_object(static_cast<QV4::NoThrowContext*>(context)); MOTH_END_INSTR(LoadScopeObject) + MOTH_BEGIN_INSTR(LoadQmlSingleton) + VALUE(instr.result) = __qmljs_get_qml_singleton(static_cast<QV4::NoThrowContext*>(context), runtimeStrings[instr.name]); + MOTH_END_INSTR(LoadQmlSingleton) + #ifdef MOTH_THREADED_INTERPRETER // nothing to do #else diff --git a/src/qml/qml/qqmlcontextwrapper.cpp b/src/qml/qml/qqmlcontextwrapper.cpp index cbfc5468fe..0b3b282061 100644 --- a/src/qml/qml/qqmlcontextwrapper.cpp +++ b/src/qml/qml/qqmlcontextwrapper.cpp @@ -412,6 +412,25 @@ ReturnedValue QmlContextWrapper::idObjectsArray() return idObjectsWrapper->asReturnedValue(); } +ReturnedValue QmlContextWrapper::qmlSingletonWrapper(const StringRef &name) +{ + if (!context->imports) + return Encode::undefined(); + // Search for attached properties, enums and imported scripts + QQmlTypeNameCache::Result r = context->imports->query(name); + + Q_ASSERT(r.isValid()); + Q_ASSERT(r.type); + Q_ASSERT(r.type->isSingleton()); + + QQmlEngine *e = v8->engine(); + QQmlType::SingletonInstanceInfo *siinfo = r.type->singletonInstanceInfo(); + siinfo->init(e); + + QObject *qobjectSingleton = siinfo->qobjectApi(e); + return QV4::QObjectWrapper::wrap(engine(), qobjectSingleton); +} + DEFINE_MANAGED_VTABLE(QQmlIdObjectsArray); QQmlIdObjectsArray::QQmlIdObjectsArray(ExecutionEngine *engine, QmlContextWrapper *contextWrapper) diff --git a/src/qml/qml/qqmlcontextwrapper_p.h b/src/qml/qml/qqmlcontextwrapper_p.h index 603a5af2fd..89ace7090c 100644 --- a/src/qml/qml/qqmlcontextwrapper_p.h +++ b/src/qml/qml/qqmlcontextwrapper_p.h @@ -97,6 +97,7 @@ struct Q_QML_EXPORT QmlContextWrapper : Object static void registerQmlDependencies(ExecutionEngine *context, const CompiledData::Function *compiledFunction); ReturnedValue idObjectsArray(); + ReturnedValue qmlSingletonWrapper(const StringRef &name); QV8Engine *v8; // ### temporary, remove bool readOnly; diff --git a/src/qml/qml/qqmlmetatype.cpp b/src/qml/qml/qqmlmetatype.cpp index 342d1dc69c..ed0c0afd6f 100644 --- a/src/qml/qml/qqmlmetatype.cpp +++ b/src/qml/qml/qqmlmetatype.cpp @@ -225,17 +225,21 @@ public: void QQmlType::SingletonInstanceInfo::init(QQmlEngine *e) { QV4::ExecutionEngine *v4 = QV8Engine::getV4(e->handle()); - v4->pushGlobalContext(); if (scriptCallback && scriptApi(e).isUndefined()) { + v4->pushGlobalContext(); setScriptApi(e, scriptCallback(e, e)); + v4->popContext(); } else if (qobjectCallback && !qobjectApi(e)) { + v4->pushGlobalContext(); setQObjectApi(e, qobjectCallback(e, e)); + v4->popContext(); } else if (!url.isEmpty() && !qobjectApi(e)) { + v4->pushGlobalContext(); QQmlComponent component(e, url, QQmlComponent::PreferSynchronous); QObject *o = component.create(); setQObjectApi(e, o); + v4->popContext(); } - v4->popContext(); } void QQmlType::SingletonInstanceInfo::destroy(QQmlEngine *e) |