aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--.qmake.conf2
-rw-r--r--examples/quick/scenegraph/openglunderqml/squircle.cpp5
-rw-r--r--src/qml/compiler/qqmlcodegenerator.cpp176
-rw-r--r--src/qml/compiler/qqmlcodegenerator_p.h8
-rw-r--r--src/qml/compiler/qv4codegen.cpp2
-rw-r--r--src/qml/compiler/qv4codegen_p.h3
-rw-r--r--src/qml/compiler/qv4instr_moth_p.h26
-rw-r--r--src/qml/compiler/qv4isel_masm.cpp48
-rw-r--r--src/qml/compiler/qv4isel_masm_p.h36
-rw-r--r--src/qml/compiler/qv4isel_moth.cpp28
-rw-r--r--src/qml/compiler/qv4isel_moth_p.h11
-rw-r--r--src/qml/compiler/qv4isel_p.cpp16
-rw-r--r--src/qml/compiler/qv4isel_p.h7
-rw-r--r--src/qml/compiler/qv4jsir.cpp52
-rw-r--r--src/qml/compiler/qv4jsir_p.h86
-rw-r--r--src/qml/compiler/qv4regalloc.cpp12
-rw-r--r--src/qml/compiler/qv4ssa.cpp125
-rw-r--r--src/qml/compiler/qv4ssa_p.h3
-rw-r--r--src/qml/jsruntime/qv4argumentsobject.cpp103
-rw-r--r--src/qml/jsruntime/qv4argumentsobject_p.h10
-rw-r--r--src/qml/jsruntime/qv4context.cpp68
-rw-r--r--src/qml/jsruntime/qv4context_p.h29
-rw-r--r--src/qml/jsruntime/qv4engine.cpp18
-rw-r--r--src/qml/jsruntime/qv4engine_p.h1
-rw-r--r--src/qml/jsruntime/qv4functionobject.cpp7
-rw-r--r--src/qml/jsruntime/qv4mm.cpp50
-rw-r--r--src/qml/jsruntime/qv4mm_p.h12
-rw-r--r--src/qml/jsruntime/qv4object.cpp2
-rw-r--r--src/qml/jsruntime/qv4objectiterator.cpp11
-rw-r--r--src/qml/jsruntime/qv4objectproto.cpp7
-rw-r--r--src/qml/jsruntime/qv4runtime.cpp26
-rw-r--r--src/qml/jsruntime/qv4runtime_p.h6
-rw-r--r--src/qml/jsruntime/qv4script.cpp22
-rw-r--r--src/qml/jsruntime/qv4vme_moth.cpp23
-rw-r--r--src/qml/qml/qqmlcompiler.cpp2
-rw-r--r--src/qml/qml/qqmlcontextwrapper.cpp77
-rw-r--r--src/qml/qml/qqmlcontextwrapper_p.h18
-rw-r--r--src/qml/qml/qqmlengine.cpp2
-rw-r--r--src/qml/qml/qqmlengine_p.h15
-rw-r--r--src/qml/qml/qqmlmetatype.cpp8
-rw-r--r--src/qml/qml/qqmltypeloader.cpp2
-rw-r--r--src/qml/util/qqmladaptormodel.cpp6
-rw-r--r--src/quick/doc/src/concepts/visualcanvas/scenegraph.qdoc5
-rw-r--r--src/quick/items/qquickflickable.cpp6
-rw-r--r--src/quick/items/qquickitemview.cpp2
-rw-r--r--src/quick/items/qquickshadereffect.cpp1
-rw-r--r--src/quick/items/qquickshadereffectnode.cpp6
-rw-r--r--src/quick/items/qquickwindow.cpp17
-rw-r--r--src/quick/scenegraph/qsgrenderloop.cpp1
-rw-r--r--src/quick/scenegraph/qsgwindowsrenderloop.cpp13
-rw-r--r--src/quick/util/qquicksmoothedanimation.cpp3
-rw-r--r--tests/auto/qml/animation/qpauseanimationjob/tst_qpauseanimationjob.cpp51
-rw-r--r--tests/auto/qml/debugger/shared/qqmldebugclient.cpp1
-rw-r--r--tests/auto/qml/qqmlxmlhttprequest/tst_qqmlxmlhttprequest.cpp295
-rw-r--r--tests/auto/quick/qquickitem/tst_qquickitem.cpp25
-rw-r--r--tests/auto/quick/qquicklistview/data/headerchangesviewport.qml19
-rw-r--r--tests/auto/quick/qquicklistview/data/typedModel.qml23
-rw-r--r--tests/auto/quick/qquicklistview/tst_qquicklistview.cpp50
-rw-r--r--tests/auto/shared/testhttpserver.cpp53
-rw-r--r--tests/auto/shared/testhttpserver.h9
60 files changed, 1122 insertions, 629 deletions
diff --git a/.qmake.conf b/.qmake.conf
index b0bc49d477..a0d132328a 100644
--- a/.qmake.conf
+++ b/.qmake.conf
@@ -2,5 +2,5 @@ load(qt_build_config)
CONFIG += qt_example_installs
CONFIG += warning_clean
-MODULE_VERSION = 5.2.0
+MODULE_VERSION = 5.2.1
diff --git a/examples/quick/scenegraph/openglunderqml/squircle.cpp b/examples/quick/scenegraph/openglunderqml/squircle.cpp
index 8ceb9c5f9e..91d69c90a4 100644
--- a/examples/quick/scenegraph/openglunderqml/squircle.cpp
+++ b/examples/quick/scenegraph/openglunderqml/squircle.cpp
@@ -129,7 +129,10 @@ void Squircle::paint()
m_program->setAttributeArray(0, GL_FLOAT, values, 2);
m_program->setUniformValue("t", (float) m_thread_t);
- glViewport(0, 0, window()->width(), window()->height());
+ qreal ratio = window()->devicePixelRatio();
+ int w = int(ratio * window()->width());
+ int h = int(ratio * window()->height());
+ glViewport(0, 0, w, h);
glDisable(GL_DEPTH_TEST);
diff --git a/src/qml/compiler/qqmlcodegenerator.cpp b/src/qml/compiler/qqmlcodegenerator.cpp
index 2215551b95..c32ad2958d 100644
--- a/src/qml/compiler/qqmlcodegenerator.cpp
+++ b/src/qml/compiler/qqmlcodegenerator.cpp
@@ -1208,6 +1208,12 @@ JSCodeGen::JSCodeGen(QQmlEnginePrivate *enginePrivate, const QString &fileName,
, jsEngine(jsEngine)
, qmlRoot(qmlRoot)
, imports(imports)
+ , _contextObject(0)
+ , _scopeObject(0)
+ , _contextObjectTemp(-1)
+ , _scopeObjectTemp(-1)
+ , _importedScriptsTemp(-1)
+ , _idArrayTemp(-1)
{
_module = jsModule;
_module->setFileName(fileName);
@@ -1318,51 +1324,104 @@ QQmlPropertyData *JSCodeGen::lookupQmlCompliantProperty(QQmlPropertyCache *cache
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()) {
+static void initMetaObjectResolver(V4IR::MemberExpressionResolver *resolver, QQmlPropertyCache *metaObject);
- bool propertySuitable = baseAsMember->property->isFinal();
+enum MetaObjectResolverFlags {
+ AllPropertiesAreFinal = 0x1,
+ LookupsIncludeEnums = 0x2,
+ LookupsExcludeProperties = 0x4
+};
- 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 V4IR::Type resolveMetaObjectProperty(QQmlEnginePrivate *qmlEngine, V4IR::MemberExpressionResolver *resolver, V4IR::Member *member)
+{
+ V4IR::Type result = V4IR::VarType;
+ 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;
}
+ }
+ }
- // 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;
+ if (qmlEngine && !(resolver->flags & LookupsExcludeProperties)) {
+ QQmlPropertyData *property = member->property;
+ if (!property && metaObject) {
+ 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.
}
}
}
- 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;
+ resolver->flags = 0;
+}
+
+void JSCodeGen::beginFunctionBodyHook()
+{
+ _contextObjectTemp = _block->newTemp();
+ _scopeObjectTemp = _block->newTemp();
+ _importedScriptsTemp = _block->newTemp();
+ _idArrayTemp = _block->newTemp();
+
+ V4IR::Temp *temp = _block->TEMP(_contextObjectTemp);
+ initMetaObjectResolver(&temp->memberResolver, _contextObject);
+ move(temp, _block->NAME(V4IR::Name::builtin_qml_context_object, 0, 0));
+
+ temp = _block->TEMP(_scopeObjectTemp);
+ initMetaObjectResolver(&temp->memberResolver, _scopeObject);
+ move(temp, _block->NAME(V4IR::Name::builtin_qml_scope_object, 0, 0));
+
+ move(_block->TEMP(_importedScriptsTemp), _block->NAME(V4IR::Name::builtin_qml_imported_scripts_object, 0, 0));
+ move(_block->TEMP(_idArrayTemp), _block->NAME(V4IR::Name::builtin_qml_id_array, 0, 0));
}
V4IR::Expr *JSCodeGen::fallbackNameLookup(const QString &name, int line, int col)
{
+ Q_UNUSED(line)
+ Q_UNUSED(col)
// Implement QML lookup semantics in the current file context.
//
// Note: We do not check if properties of the qml scope object or context object
@@ -1378,17 +1437,52 @@ V4IR::Expr *JSCodeGen::fallbackNameLookup(const QString &name, int line, int col
foreach (const IdMapping &mapping, _idObjects)
if (name == mapping.name) {
_function->idObjectDependencies.insert(mapping.idIndex);
- return _block->QML_CONTEXT_MEMBER(_block->NAME(V4IR::Name::builtin_qml_id_scope, line, col),
- _function->newString(mapping.name), mapping.idIndex);
+ V4IR::Expr *s = subscript(_block->TEMP(_idArrayTemp), _block->CONST(V4IR::SInt32Type, mapping.idIndex));
+ V4IR::Temp *result = _block->TEMP(_block->newTemp());
+ initMetaObjectResolver(&result->memberResolver, mapping.type);
+ _block->MOVE(result, s);
+ result = _block->TEMP(result->index);
+ result->isReadOnly = true; // don't allow use as lvalue
+ return result;
}
{
QQmlTypeNameCache::Result r = imports->query(name);
if (r.isValid()) {
- if (r.scriptIndex != -1)
- return subscript(_block->NAME(V4IR::Name::builtin_qml_imported_scripts_object, line, col), _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.
+ }
}
}
@@ -1400,9 +1494,9 @@ 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);
+ V4IR::Temp *base = _block->TEMP(_scopeObjectTemp);
+ initMetaObjectResolver(&base->memberResolver, _scopeObject);
+ return _block->MEMBER(base, _function->newString(name), pd);
}
}
@@ -1414,9 +1508,9 @@ 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);
+ V4IR::Temp *base = _block->TEMP(_contextObjectTemp);
+ initMetaObjectResolver(&base->memberResolver, _contextObject);
+ return _block->MEMBER(base, _function->newString(name), pd);
}
}
diff --git a/src/qml/compiler/qqmlcodegenerator_p.h b/src/qml/compiler/qqmlcodegenerator_p.h
index a5fec65111..f16f910078 100644
--- a/src/qml/compiler/qqmlcodegenerator_p.h
+++ b/src/qml/compiler/qqmlcodegenerator_p.h
@@ -364,10 +364,8 @@ 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 void beginFunctionBodyHook();
virtual V4IR::Expr *fallbackNameLookup(const QString &name, int line, int col);
private:
@@ -382,6 +380,10 @@ private:
ObjectIdMapping _idObjects;
QQmlPropertyCache *_contextObject;
QQmlPropertyCache *_scopeObject;
+ int _contextObjectTemp;
+ int _scopeObjectTemp;
+ int _importedScriptsTemp;
+ int _idArrayTemp;
};
} // namespace QtQml
diff --git a/src/qml/compiler/qv4codegen.cpp b/src/qml/compiler/qv4codegen.cpp
index 893abc9659..a8338f8656 100644
--- a/src/qml/compiler/qv4codegen.cpp
+++ b/src/qml/compiler/qv4codegen.cpp
@@ -2050,6 +2050,8 @@ int Codegen::defineFunction(const QString &name, AST::Node *ast,
ast->firstSourceLocation().startLine, ast->firstSourceLocation().startColumn), 0));
}
+ beginFunctionBodyHook();
+
sourceElements(body);
_function->insertBasicBlock(_exitBlock);
diff --git a/src/qml/compiler/qv4codegen_p.h b/src/qml/compiler/qv4codegen_p.h
index de22e8904b..32f1f1bfd4 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);
@@ -330,6 +330,7 @@ protected:
V4IR::Expr *identifier(const QString &name, int line = 0, int col = 0);
// Hook provided to implement QML lookup semantics
virtual V4IR::Expr *fallbackNameLookup(const QString &name, int line, int col);
+ virtual void beginFunctionBodyHook() {}
// nodes
virtual bool visit(AST::ArgumentList *ast);
diff --git a/src/qml/compiler/qv4instr_moth_p.h b/src/qml/compiler/qv4instr_moth_p.h
index 9baf7f89ca..180391ff33 100644
--- a/src/qml/compiler/qv4instr_moth_p.h
+++ b/src/qml/compiler/qv4instr_moth_p.h
@@ -98,6 +98,7 @@ QT_BEGIN_NAMESPACE
F(CallBuiltinConvertThisToObject, callBuiltinConvertThisToObject) \
F(CreateValue, createValue) \
F(CreateProperty, createProperty) \
+ F(ConstructPropertyLookup, constructPropertyLookup) \
F(CreateActivationProperty, createActivationProperty) \
F(ConstructGlobalLookup, constructGlobalLookup) \
F(Jump, jump) \
@@ -125,10 +126,11 @@ QT_BEGIN_NAMESPACE
F(MulNumberParams, mulNumberParams) \
F(SubNumberParams, subNumberParams) \
F(LoadThis, loadThis) \
- F(LoadQmlIdObject, loadQmlIdObject) \
+ 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
@@ -491,6 +493,14 @@ union Instr
Param base;
Param result;
};
+ struct instr_constructPropertyLookup {
+ MOTH_INSTR_HEADER
+ int index;
+ quint32 argc;
+ quint32 callData;
+ Param base;
+ Param result;
+ };
struct instr_createActivationProperty {
MOTH_INSTR_HEADER
int name;
@@ -645,10 +655,9 @@ union Instr
MOTH_INSTR_HEADER
Param result;
};
- struct instr_loadQmlIdObject {
+ struct instr_loadQmlIdArray {
MOTH_INSTR_HEADER
Param result;
- int id;
};
struct instr_loadQmlImportedScripts {
MOTH_INSTR_HEADER
@@ -662,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;
@@ -712,6 +726,7 @@ union Instr
instr_callBuiltinConvertThisToObject callBuiltinConvertThisToObject;
instr_createValue createValue;
instr_createProperty createProperty;
+ instr_constructPropertyLookup constructPropertyLookup;
instr_createActivationProperty createActivationProperty;
instr_constructGlobalLookup constructGlobalLookup;
instr_jump jump;
@@ -739,10 +754,11 @@ union Instr
instr_mulNumberParams mulNumberParams;
instr_subNumberParams subNumberParams;
instr_loadThis loadThis;
- instr_loadQmlIdObject loadQmlIdObject;
+ instr_loadQmlIdArray loadQmlIdArray;
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 a999dd4da1..ed57852cd6 100644
--- a/src/qml/compiler/qv4isel_masm.cpp
+++ b/src/qml/compiler/qv4isel_masm.cpp
@@ -439,15 +439,6 @@ static void printDisassembledOutputWithCalls(const char* output, const QHash<voi
}
#endif
-void Assembler::recordLineNumber(int lineNumber)
-{
- CodeLineNumerMapping mapping;
- mapping.location = label();
- mapping.lineNumber = lineNumber;
- codeLineNumberMappings << mapping;
-}
-
-
JSC::MacroAssemblerCodeRef Assembler::link(int *codeSize)
{
Label endOfCode = label();
@@ -467,14 +458,6 @@ JSC::MacroAssemblerCodeRef Assembler::link(int *codeSize)
JSC::JSGlobalData dummy(_executableAllocator);
JSC::LinkBuffer linkBuffer(dummy, this, 0);
- QVector<uint> lineNumberMapping(codeLineNumberMappings.count() * 2);
-
- for (int i = 0; i < codeLineNumberMappings.count(); ++i) {
- lineNumberMapping[i * 2] = linkBuffer.offsetOf(codeLineNumberMappings.at(i).location);
- lineNumberMapping[i * 2 + 1] = codeLineNumberMappings.at(i).lineNumber;
- }
- _isel->jsUnitGenerator()->registerLineNumberMapping(_function, lineNumberMapping);
-
QHash<void*, const char*> functions;
foreach (CallToLink ctl, _callsToLink) {
linkBuffer.link(ctl.call, ctl.externalFunction);
@@ -556,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());
@@ -578,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();
@@ -642,9 +626,9 @@ void InstructionSelection::run(int functionIndex)
foreach (V4IR::Stmt *s, _block->statements) {
if (s->location.isValid()) {
- _as->recordLineNumber(s->location.startLine);
if (int(s->location.startLine) != lastLine) {
- _as->saveInstructionPointer(Assembler::ScratchRegister);
+ Assembler::Address lineAddr(Assembler::ContextRegister, qOffsetOf(QV4::ExecutionContext, lineNumber));
+ _as->store32(Assembler::TrustedImm32(s->location.startLine), lineAddr);
lastLine = s->location.startLine;
}
}
@@ -896,9 +880,9 @@ void InstructionSelection::loadThisObject(V4IR::Temp *temp)
#endif
}
-void InstructionSelection::loadQmlIdObject(int id, V4IR::Temp *temp)
+void InstructionSelection::loadQmlIdArray(V4IR::Temp *temp)
{
- generateFunctionCall(temp, __qmljs_get_id_object, Assembler::ContextRegister, Assembler::TrustedImm32(id));
+ generateFunctionCall(temp, __qmljs_get_id_array, Assembler::ContextRegister);
}
void InstructionSelection::loadQmlImportedScripts(V4IR::Temp *temp)
@@ -916,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) {
@@ -1786,9 +1775,18 @@ void InstructionSelection::constructActivationProperty(V4IR::Name *func, V4IR::E
void InstructionSelection::constructProperty(V4IR::Temp *base, const QString &name, V4IR::ExprList *args, V4IR::Temp *result)
{
- prepareCallData(args, 0);
+ prepareCallData(args, base);
+ if (useFastLookups) {
+ uint index = registerGetterLookup(name);
+ generateFunctionCall(result, __qmljs_construct_property_lookup,
+ Assembler::ContextRegister,
+ Assembler::TrustedImm32(index),
+ baseAddressForCallData());
+ return;
+ }
+
generateFunctionCall(result, __qmljs_construct_property, Assembler::ContextRegister,
- Assembler::Reference(base), Assembler::PointerToString(name),
+ Assembler::PointerToString(name),
baseAddressForCallData());
}
diff --git a/src/qml/compiler/qv4isel_masm_p.h b/src/qml/compiler/qv4isel_masm_p.h
index e3b41857ea..4b0d19df07 100644
--- a/src/qml/compiler/qv4isel_masm_p.h
+++ b/src/qml/compiler/qv4isel_masm_p.h
@@ -466,23 +466,6 @@ public:
V4IR::BasicBlock *block;
};
- void saveInstructionPointer(RegisterID freeScratchRegister) {
- Address ipAddr(ContextRegister, qOffsetOf(QV4::ExecutionContext, jitInstructionPointer));
- RegisterID sourceRegister = freeScratchRegister;
-
-#if CPU(X86_64) || CPU(X86)
- callToRetrieveIP();
- peek(sourceRegister);
- pop();
-#elif CPU(ARM)
- move(JSC::ARMRegisters::pc, sourceRegister);
-#else
-#error "Port me!"
-#endif
-
- storePtr(sourceRegister, ipAddr);
- }
-
void callAbsolute(const char* functionName, FunctionPtr function) {
CallToLink ctl;
ctl.call = call();
@@ -1397,8 +1380,6 @@ public:
JSC::MacroAssemblerCodeRef link(int *codeSize);
- void recordLineNumber(int lineNumber);
-
const StackLayout stackLayout() const { return _stackLayout; }
ConstantTable &constantTable() { return _constTable; }
@@ -1424,13 +1405,6 @@ private:
QV4::ExecutableAllocator *_executableAllocator;
InstructionSelection *_isel;
-
- struct CodeLineNumerMapping
- {
- Assembler::Label location;
- int lineNumber;
- };
- QVector<CodeLineNumerMapping> codeLineNumberMappings;
};
template <typename T> inline void prepareRelativeCall(const T &, Assembler *){}
@@ -1445,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);
@@ -1483,10 +1457,11 @@ protected:
virtual void callSubscript(V4IR::Expr *base, V4IR::Expr *index, V4IR::ExprList *args, V4IR::Temp *result);
virtual void convertType(V4IR::Temp *source, V4IR::Temp *target);
virtual void loadThisObject(V4IR::Temp *temp);
- virtual void loadQmlIdObject(int id, V4IR::Temp *temp);
+ virtual void loadQmlIdArray(V4IR::Temp *temp);
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);
@@ -1655,14 +1630,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 6db8f11a9e..ee7e8ce2e8 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);
@@ -351,6 +352,16 @@ void InstructionSelection::constructActivationProperty(V4IR::Name *func,
void InstructionSelection::constructProperty(V4IR::Temp *base, const QString &name, V4IR::ExprList *args, V4IR::Temp *result)
{
+ if (useFastLookups) {
+ Instruction::ConstructPropertyLookup call;
+ call.base = getParam(base);
+ call.index = registerGetterLookup(name);
+ prepareCallArgs(args, call.argc);
+ call.callData = callDataStart();
+ call.result = getResultParam(result);
+ addInstruction(call);
+ return;
+ }
Instruction::CreateProperty create;
create.base = getParam(base);
create.name = registerString(name);
@@ -377,11 +388,10 @@ void InstructionSelection::loadThisObject(V4IR::Temp *temp)
addInstruction(load);
}
-void InstructionSelection::loadQmlIdObject(int id, V4IR::Temp *temp)
+void InstructionSelection::loadQmlIdArray(V4IR::Temp *temp)
{
- Instruction::LoadQmlIdObject load;
+ Instruction::LoadQmlIdArray load;
load.result = getResultParam(temp);
- load.id = id;
addInstruction(load);
}
@@ -406,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 ffb8ff4539..031c2d838a 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);
@@ -112,10 +112,11 @@ protected:
virtual void constructProperty(V4IR::Temp *base, const QString &name, V4IR::ExprList *args, V4IR::Temp *result);
virtual void constructValue(V4IR::Temp *value, V4IR::ExprList *args, V4IR::Temp *result);
virtual void loadThisObject(V4IR::Temp *temp);
- virtual void loadQmlIdObject(int id, V4IR::Temp *temp);
+ virtual void loadQmlIdArray(V4IR::Temp *temp);
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);
@@ -168,6 +169,8 @@ private:
void patchJumpAddresses();
QByteArray squeezeCode() const;
+ QQmlEnginePrivate *qmlEngine;
+
V4IR::BasicBlock *_block;
V4IR::BasicBlock *_nextBlock;
@@ -189,8 +192,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.cpp b/src/qml/compiler/qv4isel_p.cpp
index 45b1e9f3b0..96a3370903 100644
--- a/src/qml/compiler/qv4isel_p.cpp
+++ b/src/qml/compiler/qv4isel_p.cpp
@@ -103,12 +103,16 @@ void IRDecoder::visitMove(V4IR::Move *s)
if (V4IR::Name *n = s->source->asName()) {
if (n->id && *n->id == QStringLiteral("this")) // TODO: `this' should be a builtin.
loadThisObject(t);
+ else if (n->builtin == V4IR::Name::builtin_qml_id_array)
+ loadQmlIdArray(t);
else if (n->builtin == V4IR::Name::builtin_qml_context_object)
loadQmlContextObject(t);
else if (n->builtin == V4IR::Name::builtin_qml_scope_object)
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;
@@ -142,15 +146,7 @@ void IRDecoder::visitMove(V4IR::Move *s)
return;
}
} else if (V4IR::Member *m = s->source->asMember()) {
- if (m->type == V4IR::Member::MemberOfQmlContext) {
- V4IR::Name *base = m->base->asName();
- Q_ASSERT(base);
-
- if (base->builtin == V4IR::Name::builtin_qml_id_scope) {
- loadQmlIdObject(m->memberIndex, t);
- return;
- }
- } else if (m->type == V4IR::Member::MemberOfQObject) {
+ if (m->property) {
bool captureRequired = true;
if (_function) {
captureRequired = !_function->contextObjectDependencies.contains(m->property)
@@ -195,7 +191,7 @@ void IRDecoder::visitMove(V4IR::Move *s)
} else if (V4IR::Member *m = s->target->asMember()) {
if (m->base->asTemp() || m->base->asConst()) {
if (s->source->asTemp() || s->source->asConst()) {
- if (m->type == V4IR::Member::MemberOfQObject) {
+ if (m->property) {
setQObjectProperty(s->source, m->base, m->property->coreIndex);
return;
} else {
diff --git a/src/qml/compiler/qv4isel_p.h b/src/qml/compiler/qv4isel_p.h
index 23ef7cc69e..7ee5cbba4e 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;
};
@@ -142,10 +144,11 @@ public: // to implement by subclasses:
virtual void constructProperty(V4IR::Temp *base, const QString &name, V4IR::ExprList *args, V4IR::Temp *result) = 0;
virtual void constructValue(V4IR::Temp *value, V4IR::ExprList *args, V4IR::Temp *result) = 0;
virtual void loadThisObject(V4IR::Temp *temp) = 0;
- virtual void loadQmlIdObject(int id, V4IR::Temp *temp) = 0;
+ virtual void loadQmlIdArray(V4IR::Temp *temp) = 0;
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 75261b2469..41502dbd4f 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) {
@@ -363,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;
}
@@ -372,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;
}
@@ -381,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;
}
@@ -424,8 +439,8 @@ static const char *builtin_to_string(Name::Builtin b)
return "builtin_setup_argument_object";
case V4IR::Name::builtin_convert_this_to_object:
return "builtin_convert_this_to_object";
- case V4IR::Name::builtin_qml_id_scope:
- return "builtin_qml_id_scope";
+ case V4IR::Name::builtin_qml_id_array:
+ return "builtin_qml_id_array";
case V4IR::Name::builtin_qml_imported_scripts_object:
return "builtin_qml_imported_scripts_object";
case V4IR::Name::builtin_qml_scope_object:
@@ -541,7 +556,7 @@ void Member::dump(QTextStream &out) const
{
base->dump(out);
out << '.' << *name;
- if (type == MemberOfQObject)
+ if (property)
out << " (meta-property " << property->coreIndex << " <" << QMetaType::typeName(property->propType) << ">)";
}
@@ -825,24 +840,10 @@ Expr *BasicBlock::SUBSCRIPT(Expr *base, Expr *index)
return e;
}
-Expr *BasicBlock::MEMBER(Expr *base, const QString *name)
-{
- Member*e = function->New<Member>();
- e->init(base, name);
- return e;
-}
-
-Expr *BasicBlock::QML_CONTEXT_MEMBER(Expr *base, const QString *id, int memberIndex)
+Expr *BasicBlock::MEMBER(Expr *base, const QString *name, QQmlPropertyData *property)
{
Member*e = function->New<Member>();
- e->initQmlContextMember(base, id, memberIndex);
- return e;
-}
-
-Expr *BasicBlock::QML_QOBJECT_PROPERTY(Expr *base, const QString *id, QQmlPropertyData *property)
-{
- Member*e = function->New<Member>();
- e->initMetaProperty(base, id, property);
+ e->init(base, name, property);
return e;
}
@@ -1032,14 +1033,7 @@ void CloneExpr::visitSubscript(Subscript *e)
void CloneExpr::visitMember(Member *e)
{
- if (e->type == Member::MemberByName)
- cloned = block->MEMBER(clone(e->base), e->name);
- else if (e->type == Member::MemberOfQmlContext)
- cloned = block->QML_CONTEXT_MEMBER(clone(e->base), e->name, e->memberIndex);
- else if (e->type == Member::MemberOfQObject)
- cloned = block->QML_QOBJECT_PROPERTY(clone(e->base), e->name, e->property);
- else
- Q_ASSERT(!"Unimplemented!");
+ cloned = block->MEMBER(clone(e->base), e->name, e->property);
}
} // end of namespace IR
diff --git a/src/qml/compiler/qv4jsir_p.h b/src/qml/compiler/qv4jsir_p.h
index 9a1bd87a1d..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>
@@ -73,6 +74,8 @@ QT_BEGIN_NAMESPACE
class QTextStream;
class QQmlType;
class QQmlPropertyData;
+class QQmlPropertyCache;
+class QQmlEnginePrivate;
namespace QV4 {
struct ExecutionContext;
@@ -122,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,
@@ -181,7 +192,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 +230,22 @@ struct StmtVisitor {
virtual void visitPhi(Phi *) = 0;
};
+
+struct MemberExpressionResolver
+{
+ typedef Type (*ResolveFunction)(QQmlEnginePrivate *engine, MemberExpressionResolver *resolver, Member *member);
+
+ MemberExpressionResolver()
+ : 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 {
Type type;
@@ -325,7 +353,7 @@ struct Name: Expr {
builtin_define_object_literal,
builtin_setup_argument_object,
builtin_convert_this_to_object,
- builtin_qml_id_scope,
+ builtin_qml_id_array,
builtin_qml_imported_scripts_object,
builtin_qml_context_object,
builtin_qml_scope_object
@@ -333,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;
@@ -360,9 +390,12 @@ struct Temp: Expr {
};
unsigned index;
- unsigned scope : 28; // how many scopes outside the current one?
+ unsigned scope : 27; // how many scopes outside the current one?
unsigned kind : 3;
unsigned isArgumentsOrEval : 1;
+ unsigned isReadOnly : 1;
+ // Used when temp is used as base in member expression
+ MemberExpressionResolver memberResolver;
void init(unsigned kind, unsigned index, unsigned scope)
{
@@ -374,10 +407,11 @@ struct Temp: Expr {
this->index = index;
this->scope = scope;
this->isArgumentsOrEval = false;
+ this->isReadOnly = false;
}
virtual void accept(ExprVisitor *v) { v->visitTemp(this); }
- virtual bool isLValue() { return true; }
+ virtual bool isLValue() { return !isReadOnly; }
virtual Temp *asTemp() { return this; }
virtual void dump(QTextStream &out) const;
@@ -518,47 +552,22 @@ struct Subscript: Expr {
};
struct Member: Expr {
- enum MemberType {
- MemberByName,
- // QML extensions
- MemberOfQmlContext, // lookup in context's id values
- MemberOfQObject
- };
-
- MemberType type;
Expr *base;
const QString *name;
- int memberIndex; // used if type == MemberOfQmlContext
QQmlPropertyData *property;
+ int enumValue;
+ bool memberIsEnum;
- void init(Expr *base, const QString *name)
+ void init(Expr *base, const QString *name, QQmlPropertyData *property = 0)
{
- this->type = MemberByName;
- this->base = base;
- this->name = name;
- this->memberIndex = -1;
- this->property = 0;
- }
-
- void initQmlContextMember(Expr *base, const QString *name, int memberIndex)
- {
- this->type = MemberOfQmlContext;
- this->base = base;
- this->name = name;
- this->memberIndex = memberIndex;
- this->property = 0;
- }
-
- void initMetaProperty(Expr *base, const QString *name, QQmlPropertyData *property)
- {
- this->type = MemberOfQObject;
this->base = base;
this->name = name;
this->property = property;
+ this->memberIsEnum = false;
}
virtual void accept(ExprVisitor *v) { v->visitMember(this); }
- virtual bool isLValue() { return type != MemberOfQmlContext; }
+ virtual bool isLValue() { return true; }
virtual Member *asMember() { return this; }
virtual void dump(QTextStream &out) const;
@@ -860,9 +869,7 @@ struct BasicBlock {
Expr *CALL(Expr *base, ExprList *args = 0);
Expr *NEW(Expr *base, ExprList *args = 0);
Expr *SUBSCRIPT(Expr *base, Expr *index);
- Expr *MEMBER(Expr *base, const QString *name);
- Expr *QML_CONTEXT_MEMBER(Expr *base, const QString *id, int memberIndex);
- Expr *QML_QOBJECT_PROPERTY(Expr *base, const QString *id, QQmlPropertyData *property);
+ Expr *MEMBER(Expr *base, const QString *name, QQmlPropertyData *property = 0);
Stmt *EXP(Expr *expr);
@@ -927,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;
@@ -937,6 +946,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..5d1dc14500 100644
--- a/src/qml/compiler/qv4regalloc.cpp
+++ b/src/qml/compiler/qv4regalloc.cpp
@@ -338,9 +338,8 @@ protected: // IRDecoder
addDef(temp);
}
- virtual void loadQmlIdObject(int id, V4IR::Temp *temp)
+ virtual void loadQmlIdArray(V4IR::Temp *temp)
{
- Q_UNUSED(id);
addDef(temp);
addCall();
}
@@ -365,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);
@@ -589,6 +596,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..f9acf99a65 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>
@@ -1188,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")))
@@ -1209,6 +1212,7 @@ protected:
e->expr->accept(this);
switch (e->expr->type) {
+ case QObjectType:
case StringType:
case VarType:
markAsSideEffect();
@@ -1227,7 +1231,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 +1247,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 +1279,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 +1360,7 @@ private:
class PropagateTempTypes: public StmtVisitor, ExprVisitor
{
public:
- PropagateTempTypes(const QHash<Temp, int> &tempTypes)
+ PropagateTempTypes(const QHash<Temp, DiscoveredType> &tempTypes)
: _tempTypes(tempTypes)
{}
@@ -1352,7 +1376,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 +1421,7 @@ private:
}
private:
- QHash<Temp, int> _tempTypes;
+ QHash<Temp, DiscoveredType> _tempTypes;
};
private:
@@ -1429,13 +1457,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 +1478,7 @@ private:
_worklist += QSet<Stmt *>::fromList(_defUses.uses(*t));
}
} else {
- e->type = (Type) ty;
+ e->type = (Type) ty.type;
}
}
@@ -1472,8 +1500,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 +1535,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 +1604,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 +1640,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 +1655,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 +1673,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)
@@ -1889,7 +1909,7 @@ protected:
// when writing undefined to them, and an exception is thrown when they're missing
// a reset function.
const Member *targetMember = s->target->asMember();
- const bool inhibitConversion = targetMember && targetMember->type == Member::MemberOfQObject && targetMember->property;
+ const bool inhibitConversion = targetMember && targetMember->property;
run(s->source, s->target->type, !inhibitConversion);
}
@@ -2356,10 +2376,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);
@@ -2494,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)) {
@@ -2570,10 +2601,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 +2988,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 +3030,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/qv4argumentsobject.cpp b/src/qml/jsruntime/qv4argumentsobject.cpp
index ed010b1230..749509c353 100644
--- a/src/qml/jsruntime/qv4argumentsobject.cpp
+++ b/src/qml/jsruntime/qv4argumentsobject.cpp
@@ -47,10 +47,11 @@ using namespace QV4;
DEFINE_MANAGED_VTABLE(ArgumentsObject);
ArgumentsObject::ArgumentsObject(CallContext *context)
- : Object(context->engine), context(context)
+ : Object(context->engine), context(context), fullyCreated(false)
{
vtbl = &static_vtbl;
type = Type_ArgumentsObject;
+ flags &= ~SimpleArray;
ExecutionEngine *v4 = context->engine;
Scope scope(v4);
@@ -60,8 +61,8 @@ ArgumentsObject::ArgumentsObject(CallContext *context)
internalClass = v4->strictArgumentsObjectClass;
Property pd = Property::fromAccessor(v4->thrower, v4->thrower);
- assert(CalleePropertyIndex == internalClass->find(context->engine->id_callee));
- assert(CallerPropertyIndex == internalClass->find(context->engine->id_caller));
+ Q_ASSERT(CalleePropertyIndex == internalClass->find(context->engine->id_callee));
+ Q_ASSERT(CallerPropertyIndex == internalClass->find(context->engine->id_caller));
memberData[CalleePropertyIndex] = pd;
memberData[CallerPropertyIndex] = pd;
@@ -69,27 +70,12 @@ ArgumentsObject::ArgumentsObject(CallContext *context)
for (int i = 0; i < context->callData->argc; ++i)
arrayData[i].value = context->callData->args[i];
arrayDataLen = context->callData->argc;
+ fullyCreated = true;
} else {
internalClass = engine()->argumentsObjectClass;
Q_ASSERT(CalleePropertyIndex == internalClass->find(context->engine->id_callee));
memberData[CalleePropertyIndex].value = context->function->asReturnedValue();
isNonStrictArgumentsObject = true;
-
- uint numAccessors = qMin((int)context->function->formalParameterCount, context->realArgumentCount);
- uint argCount = qMin(context->realArgumentCount, context->callData->argc);
- arrayReserve(argCount);
- ensureArrayAttributes();
- context->engine->requireArgumentsAccessors(numAccessors);
- for (uint i = 0; i < (uint)numAccessors; ++i) {
- mappedArguments.append(context->callData->args[i]);
- arrayData[i] = context->engine->argumentsAccessors.at(i);
- arrayAttributes[i] = Attr_Accessor;
- }
- for (uint i = numAccessors; i < argCount; ++i) {
- arrayData[i] = Property::fromValue(context->callData->args[i]);
- arrayAttributes[i] = Attr_Data;
- }
- arrayDataLen = argCount;
}
Q_ASSERT(LengthPropertyIndex == internalClass->find(context->engine->id_length));
Property *lp = memberData + ArrayObject::LengthPropertyIndex;
@@ -101,8 +87,34 @@ void ArgumentsObject::destroy(Managed *that)
static_cast<ArgumentsObject *>(that)->~ArgumentsObject();
}
+void ArgumentsObject::fullyCreate()
+{
+ if (fullyCreated)
+ return;
+
+ uint numAccessors = qMin((int)context->function->formalParameterCount, context->realArgumentCount);
+ uint argCount = qMin(context->realArgumentCount, context->callData->argc);
+ arrayReserve(argCount);
+ ensureArrayAttributes();
+ context->engine->requireArgumentsAccessors(numAccessors);
+ for (uint i = 0; i < (uint)numAccessors; ++i) {
+ mappedArguments.append(context->callData->args[i]);
+ arrayData[i] = context->engine->argumentsAccessors.at(i);
+ arrayAttributes[i] = Attr_Accessor;
+ }
+ for (uint i = numAccessors; i < argCount; ++i) {
+ arrayData[i] = Property::fromValue(context->callData->args[i]);
+ arrayAttributes[i] = Attr_Data;
+ }
+ arrayDataLen = argCount;
+
+ fullyCreated = true;
+}
+
bool ArgumentsObject::defineOwnProperty(ExecutionContext *ctx, uint index, const Property &desc, PropertyAttributes attrs)
{
+ fullyCreate();
+
Scope scope(ctx);
uint pidx = propertyIndexFromArrayIndex(index);
Property *pd = arrayData + pidx;
@@ -143,6 +155,57 @@ bool ArgumentsObject::defineOwnProperty(ExecutionContext *ctx, uint index, const
return result;
}
+ReturnedValue ArgumentsObject::getIndexed(Managed *m, uint index, bool *hasProperty)
+{
+ ArgumentsObject *args = static_cast<ArgumentsObject *>(m);
+ if (args->fullyCreated)
+ return Object::getIndexed(m, index, hasProperty);
+
+ if (index < static_cast<uint>(args->context->callData->argc)) {
+ if (hasProperty)
+ *hasProperty = true;
+ return args->context->callData->args[index].asReturnedValue();
+ }
+ return Encode::undefined();
+}
+
+void ArgumentsObject::putIndexed(Managed *m, uint index, const ValueRef value)
+{
+ ArgumentsObject *args = static_cast<ArgumentsObject *>(m);
+ if (!args->fullyCreated && index >= static_cast<uint>(args->context->callData->argc))
+ args->fullyCreate();
+
+ if (args->fullyCreated) {
+ Object::putIndexed(m, index, value);
+ return;
+ }
+
+ args->context->callData->args[index] = value;
+}
+
+bool ArgumentsObject::deleteIndexedProperty(Managed *m, uint index)
+{
+ ArgumentsObject *args = static_cast<ArgumentsObject *>(m);
+ if (!args->fullyCreated)
+ args->fullyCreate();
+ return Object::deleteIndexedProperty(m, index);
+}
+
+PropertyAttributes ArgumentsObject::queryIndexed(const Managed *m, uint index)
+{
+ const ArgumentsObject *args = static_cast<const ArgumentsObject *>(m);
+ if (args->fullyCreated)
+ return Object::queryIndexed(m, index);
+
+ uint numAccessors = qMin((int)args->context->function->formalParameterCount, args->context->realArgumentCount);
+ uint argCount = qMin(args->context->realArgumentCount, args->context->callData->argc);
+ if (index >= argCount)
+ return PropertyAttributes();
+ if (index >= numAccessors)
+ return Attr_Data;
+ return Attr_Accessor;
+}
+
DEFINE_MANAGED_VTABLE(ArgumentsGetterFunction);
ReturnedValue ArgumentsGetterFunction::call(Managed *getter, CallData *callData)
@@ -177,7 +240,7 @@ ReturnedValue ArgumentsSetterFunction::call(Managed *setter, CallData *callData)
void ArgumentsObject::markObjects(Managed *that, ExecutionEngine *e)
{
ArgumentsObject *o = static_cast<ArgumentsObject *>(that);
- o->context->mark();
+ o->context->mark(e);
for (int i = 0; i < o->mappedArguments.size(); ++i)
o->mappedArguments.at(i).mark(e);
diff --git a/src/qml/jsruntime/qv4argumentsobject_p.h b/src/qml/jsruntime/qv4argumentsobject_p.h
index 7a5b0817a3..7c58c48bcc 100644
--- a/src/qml/jsruntime/qv4argumentsobject_p.h
+++ b/src/qml/jsruntime/qv4argumentsobject_p.h
@@ -74,20 +74,26 @@ struct ArgumentsSetterFunction: FunctionObject
struct ArgumentsObject: Object {
Q_MANAGED
CallContext *context;
+ bool fullyCreated;
QVector<SafeValue> mappedArguments;
ArgumentsObject(CallContext *context);
~ArgumentsObject() {}
+
enum {
LengthPropertyIndex = 0,
CalleePropertyIndex = 1,
CallerPropertyIndex = 2
};
bool defineOwnProperty(ExecutionContext *ctx, uint index, const Property &desc, PropertyAttributes attrs);
-
+ static ReturnedValue getIndexed(Managed *m, uint index, bool *hasProperty);
+ static void putIndexed(Managed *m, uint index, const ValueRef value);
+ static bool deleteIndexedProperty(Managed *m, uint index);
+ static PropertyAttributes queryIndexed(const Managed *m, uint index);
static void markObjects(Managed *that, ExecutionEngine *e);
-protected:
static void destroy(Managed *);
+
+ void fullyCreate();
};
}
diff --git a/src/qml/jsruntime/qv4context.cpp b/src/qml/jsruntime/qv4context.cpp
index 97247ad368..372c9ce54b 100644
--- a/src/qml/jsruntime/qv4context.cpp
+++ b/src/qml/jsruntime/qv4context.cpp
@@ -51,9 +51,33 @@
using namespace QV4;
+const ManagedVTable ExecutionContext::static_vtbl =
+{
+ call,
+ construct,
+ markObjects,
+ destroy,
+ 0 /*collectDeletables*/,
+ hasInstance,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ isEqualTo,
+ 0,
+ "ExecutionContext",
+};
+
CallContext *ExecutionContext::newCallContext(FunctionObject *function, CallData *callData)
{
- CallContext *c = static_cast<CallContext *>(engine->memoryManager->allocContext(requiredMemoryForExecutionContect(function, callData->argc)));
+ CallContext *c = static_cast<CallContext *>(engine->memoryManager->allocManaged(requiredMemoryForExecutionContect(function, callData->argc)));
+ c->init();
engine->current = c;
@@ -63,7 +87,6 @@ CallContext *ExecutionContext::newCallContext(FunctionObject *function, CallData
c->realArgumentCount = callData->argc;
c->strictMode = function->strictMode;
- c->marked = false;
c->outer = function->scope;
#ifndef QT_NO_DEBUG
assert(c->outer->next != (ExecutionContext *)0x1);
@@ -92,7 +115,7 @@ CallContext *ExecutionContext::newCallContext(FunctionObject *function, CallData
WithContext *ExecutionContext::newWithContext(ObjectRef with)
{
- WithContext *w = static_cast<WithContext *>(engine->memoryManager->allocContext(sizeof(WithContext)));
+ WithContext *w = new (engine->memoryManager) WithContext;
engine->current = w;
w->initWithContext(this, with);
return w;
@@ -100,7 +123,7 @@ WithContext *ExecutionContext::newWithContext(ObjectRef with)
CatchContext *ExecutionContext::newCatchContext(const StringRef exceptionVarName, const ValueRef exceptionValue)
{
- CatchContext *c = static_cast<CatchContext *>(engine->memoryManager->allocContext(sizeof(CatchContext)));
+ CatchContext *c = new (engine->memoryManager) CatchContext;
engine->current = c;
c->initCatchContext(this, exceptionVarName, exceptionValue);
return c;
@@ -108,7 +131,8 @@ CatchContext *ExecutionContext::newCatchContext(const StringRef exceptionVarName
CallContext *ExecutionContext::newQmlContext(FunctionObject *f, ObjectRef qml)
{
- CallContext *c = static_cast<CallContext *>(engine->memoryManager->allocContext(requiredMemoryForExecutionContect(f, 0)));
+ CallContext *c = static_cast<CallContext *>(engine->memoryManager->allocManaged(requiredMemoryForExecutionContect(f, 0)));
+ c->init();
engine->current = c;
c->initQmlContext(this, qml, f);
@@ -184,6 +208,7 @@ void GlobalContext::initGlobalContext(ExecutionEngine *eng)
callData->tag = QV4::Value::_Integer_Type;
callData->argc = 0;
callData->thisObject = eng->globalObject;
+ callData->args[0] = Encode::undefined();
global = 0;
}
@@ -222,7 +247,6 @@ void CallContext::initQmlContext(ExecutionContext *parentContext, ObjectRef qml,
this->callData->thisObject = Primitive::undefinedValue();
strictMode = true;
- marked = false;
this->outer = function->scope;
#ifndef QT_NO_DEBUG
assert(outer->next != (ExecutionContext *)0x1);
@@ -285,36 +309,34 @@ bool CallContext::needsOwnArguments() const
return function->needsActivation || callData->argc < static_cast<int>(function->formalParameterCount);
}
-void ExecutionContext::mark()
+void ExecutionContext::markObjects(Managed *m, ExecutionEngine *engine)
{
- if (marked)
- return;
- marked = true;
+ ExecutionContext *ctx = static_cast<ExecutionContext *>(m);
- if (outer)
- outer->mark();
+ if (ctx->outer)
+ ctx->outer->mark(engine);
// ### shouldn't need these 3 lines
- callData->thisObject.mark(engine);
- for (int arg = 0; arg < callData->argc; ++arg)
- callData->args[arg].mark(engine);
+ ctx->callData->thisObject.mark(engine);
+ for (int arg = 0; arg < ctx->callData->argc; ++arg)
+ ctx->callData->args[arg].mark(engine);
- if (type >= Type_CallContext) {
- QV4::CallContext *c = static_cast<CallContext *>(this);
+ if (ctx->type >= Type_CallContext) {
+ QV4::CallContext *c = static_cast<CallContext *>(ctx);
for (unsigned local = 0, lastLocal = c->variableCount(); local < lastLocal; ++local)
c->locals[local].mark(engine);
if (c->activation)
c->activation->mark(engine);
c->function->mark(engine);
- } else if (type == Type_WithContext) {
- WithContext *w = static_cast<WithContext *>(this);
+ } else if (ctx->type == Type_WithContext) {
+ WithContext *w = static_cast<WithContext *>(ctx);
w->withObject->mark(engine);
- } else if (type == Type_CatchContext) {
- CatchContext *c = static_cast<CatchContext *>(this);
+ } else if (ctx->type == Type_CatchContext) {
+ CatchContext *c = static_cast<CatchContext *>(ctx);
c->exceptionVarName->mark(engine);
c->exceptionValue.mark(engine);
- } else if (type == Type_GlobalContext) {
- GlobalContext *g = static_cast<GlobalContext *>(this);
+ } else if (ctx->type == Type_GlobalContext) {
+ GlobalContext *g = static_cast<GlobalContext *>(ctx);
g->global->mark(engine);
}
}
diff --git a/src/qml/jsruntime/qv4context_p.h b/src/qml/jsruntime/qv4context_p.h
index ccb5cf98f8..e7f5ee9a9e 100644
--- a/src/qml/jsruntime/qv4context_p.h
+++ b/src/qml/jsruntime/qv4context_p.h
@@ -66,8 +66,21 @@ struct CallContext;
struct CatchContext;
struct WithContext;
-struct Q_QML_EXPORT ExecutionContext
+struct Q_QML_EXPORT ExecutionContext : public Managed
{
+ Q_MANAGED
+ ExecutionContext()
+ : Managed(0) {
+ vtbl = &static_vtbl;
+ }
+ void init() {
+ _data = 0;
+ internalClass = 0;
+ inUse = 1;
+ extensible = 1;
+ vtbl = &static_vtbl;
+ }
+
enum Type {
Type_GlobalContext = 0x1,
Type_CatchContext = 0x2,
@@ -79,7 +92,6 @@ struct Q_QML_EXPORT ExecutionContext
Type type;
bool strictMode;
- bool marked;
CallData *callData;
@@ -98,13 +110,12 @@ struct Q_QML_EXPORT ExecutionContext
EvalCode *currentEvalCode;
const uchar **interpreterInstructionPointer;
- char *jitInstructionPointer;
+ int lineNumber;
void initBaseContext(Type type, ExecutionEngine *engine, ExecutionContext *parentContext)
{
this->type = type;
strictMode = false;
- marked = false;
this->engine = engine;
parent = parentContext;
outer = 0;
@@ -112,7 +123,7 @@ struct Q_QML_EXPORT ExecutionContext
compilationUnit = 0;
currentEvalCode = 0;
interpreterInstructionPointer = 0;
- jitInstructionPointer = 0;
+ lineNumber = -1;
}
CallContext *newCallContext(FunctionObject *f, CallData *callData);
@@ -130,11 +141,11 @@ struct Q_QML_EXPORT ExecutionContext
ReturnedValue throwError(const QV4::ValueRef value);
ReturnedValue throwError(const QString &message);
ReturnedValue throwSyntaxError(const QString &message);
- ReturnedValue throwSyntaxError(const QString &message, const QString &fileName, int line, int column);
+ ReturnedValue throwSyntaxError(const QString &message, const QString &fileName, int lineNumber, int column);
ReturnedValue throwTypeError();
ReturnedValue throwTypeError(const QString &message);
ReturnedValue throwReferenceError(const ValueRef value);
- ReturnedValue throwReferenceError(const QString &value, const QString &fileName, int line, int column);
+ ReturnedValue throwReferenceError(const QString &value, const QString &fileName, int lineNumber, int column);
ReturnedValue throwRangeError(const ValueRef value);
ReturnedValue throwRangeError(const QString &message);
ReturnedValue throwURIError(const ValueRef msg);
@@ -148,10 +159,10 @@ struct Q_QML_EXPORT ExecutionContext
// Can only be called from within catch(...), rethrows if no JS exception.
ReturnedValue catchException(StackTrace *trace = 0);
- void mark();
-
inline CallContext *asCallContext();
inline const CallContext *asCallContext() const;
+
+ static void markObjects(Managed *m, ExecutionEngine *e);
};
struct CallContext : public ExecutionContext
diff --git a/src/qml/jsruntime/qv4engine.cpp b/src/qml/jsruntime/qv4engine.cpp
index 8cd059dd2b..f5a515a0ae 100644
--- a/src/qml/jsruntime/qv4engine.cpp
+++ b/src/qml/jsruntime/qv4engine.cpp
@@ -389,7 +389,8 @@ void ExecutionEngine::enableDebugger()
void ExecutionEngine::initRootContext()
{
- rootContext = static_cast<GlobalContext *>(memoryManager->allocContext(sizeof(GlobalContext) + sizeof(CallData)));
+ rootContext = static_cast<GlobalContext *>(memoryManager->allocManaged(sizeof(GlobalContext) + sizeof(CallData)));
+ rootContext->init();
current = rootContext;
current->parent = 0;
rootContext->initGlobalContext(this);
@@ -402,9 +403,9 @@ InternalClass *ExecutionEngine::newClass(const InternalClass &other)
ExecutionContext *ExecutionEngine::pushGlobalContext()
{
- GlobalContext *g = static_cast<GlobalContext *>(memoryManager->allocContext(sizeof(GlobalContext)));
+ GlobalContext *g = new (memoryManager) GlobalContext;
ExecutionContext *oldNext = g->next;
- *g = *rootContext;
+ memcpy(g, rootContext, sizeof(GlobalContext));
g->next = oldNext;
g->parent = current;
current = g;
@@ -627,11 +628,12 @@ namespace {
void resolve(StackFrame *frame, ExecutionContext *context, Function *function)
{
qptrdiff offset;
- if (context->interpreterInstructionPointer)
+ if (context->interpreterInstructionPointer) {
offset = *context->interpreterInstructionPointer - 1 - function->codeData;
- else
- offset = context->jitInstructionPointer - (char*)function->codePtr;
- frame->line = function->lineNumberForProgramCounter(offset);
+ frame->line = function->lineNumberForProgramCounter(offset);
+ } else {
+ frame->line = context->lineNumber;
+ }
}
};
}
@@ -754,7 +756,7 @@ void ExecutionEngine::markObjects()
ExecutionContext *c = current;
while (c) {
- c->mark();
+ c->mark(this);
c = c->parent;
}
diff --git a/src/qml/jsruntime/qv4engine_p.h b/src/qml/jsruntime/qv4engine_p.h
index b4972904ee..c37d4f125d 100644
--- a/src/qml/jsruntime/qv4engine_p.h
+++ b/src/qml/jsruntime/qv4engine_p.h
@@ -388,6 +388,7 @@ struct ExecutionContextSaver
inline
void Managed::mark(QV4::ExecutionEngine *engine)
{
+ Q_ASSERT(inUse);
if (markBit)
return;
markBit = 1;
diff --git a/src/qml/jsruntime/qv4functionobject.cpp b/src/qml/jsruntime/qv4functionobject.cpp
index aa1cb89a44..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"
@@ -213,7 +214,7 @@ void FunctionObject::markObjects(Managed *that, ExecutionEngine *e)
// formalParameterList[i]->mark();
// for (uint i = 0; i < varCount; ++i)
// varList[i]->mark();
- o->scope->mark();
+ o->scope->mark(e);
if (o->function)
o->function->mark(e);
@@ -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);
@@ -348,7 +349,7 @@ ReturnedValue FunctionPrototype::method_apply(CallContext *ctx)
ScopedCallData callData(scope, len);
if (len) {
- if (arr->protoHasArray() || arr->hasAccessorProperty) {
+ if (!(arr->flags & SimpleArray) || arr->protoHasArray() || arr->hasAccessorProperty) {
for (quint32 i = 0; i < len; ++i)
callData->args[i] = arr->getIndexed(i);
} else {
diff --git a/src/qml/jsruntime/qv4mm.cpp b/src/qml/jsruntime/qv4mm.cpp
index 9eb3ae7ec9..9cac0cf90c 100644
--- a/src/qml/jsruntime/qv4mm.cpp
+++ b/src/qml/jsruntime/qv4mm.cpp
@@ -155,6 +155,19 @@ struct MemoryManager::Data
QVector<Chunk> heapChunks;
+
+ struct LargeItem {
+ LargeItem *next;
+ void *data;
+
+ Managed *managed() {
+ return reinterpret_cast<Managed *>(&data);
+ }
+ };
+
+ LargeItem *largeItems;
+
+
// statistics:
#ifdef DETAILED_MM_STATS
QVector<unsigned> allocSizeCounters;
@@ -167,6 +180,7 @@ struct MemoryManager::Data
, stackTop(0)
, totalItems(0)
, totalAlloc(0)
+ , largeItems(0)
{
memset(smallItems, 0, sizeof(smallItems));
memset(nChunks, 0, sizeof(nChunks));
@@ -200,7 +214,6 @@ bool operator<(const MemoryManager::Data::Chunk &a, const MemoryManager::Data::C
MemoryManager::MemoryManager()
: m_d(new Data(true))
- , m_contextList(0)
, m_persistentValues(0)
, m_weakValues(0)
{
@@ -258,8 +271,14 @@ Managed *MemoryManager::alloc(std::size_t size)
size_t pos = size >> 4;
- // fits into a small bucket
- Q_ASSERT(size < MemoryManager::Data::MaxItemSize);
+ // doesn't fit into a small bucket
+ if (size >= MemoryManager::Data::MaxItemSize) {
+ // we use malloc for this
+ MemoryManager::Data::LargeItem *item = static_cast<MemoryManager::Data::LargeItem *>(malloc(size + sizeof(MemoryManager::Data::LargeItem)));
+ item->next = m_d->largeItems;
+ m_d->largeItems = item;
+ return item->managed();
+ }
Managed *m = m_d->smallItems[pos];
if (m)
@@ -447,18 +466,21 @@ void MemoryManager::sweep(bool lastSweep)
for (QVector<Data::Chunk>::iterator i = m_d->heapChunks.begin(), ei = m_d->heapChunks.end(); i != ei; ++i)
sweep(reinterpret_cast<char*>(i->memory.base()), i->memory.size(), i->chunkSize, &deletable);
- ExecutionContext *ctx = m_contextList;
- ExecutionContext **n = &m_contextList;
- while (ctx) {
- ExecutionContext *next = ctx->next;
- if (!ctx->marked) {
- free(ctx);
- *n = next;
- } else {
- ctx->marked = false;
- n = &ctx->next;
+ Data::LargeItem *i = m_d->largeItems;
+ Data::LargeItem **last = &m_d->largeItems;
+ while (i) {
+ Managed *m = i->managed();
+ Q_ASSERT(m->inUse);
+ if (m->markBit) {
+ m->markBit = 0;
+ last = &i->next;
+ i = i->next;
+ continue;
}
- ctx = next;
+
+ *last = i->next;
+ free(i);
+ i = *last;
}
deletable = *firstDeletable;
diff --git a/src/qml/jsruntime/qv4mm_p.h b/src/qml/jsruntime/qv4mm_p.h
index f3258519de..7d28319536 100644
--- a/src/qml/jsruntime/qv4mm_p.h
+++ b/src/qml/jsruntime/qv4mm_p.h
@@ -103,8 +103,6 @@ public:
return o;
}
- ExecutionContext *allocContext(uint size);
-
bool isGCBlocked() const;
void setGCBlocked(bool blockGC);
void runGC();
@@ -134,21 +132,11 @@ private:
protected:
QScopedPointer<Data> m_d;
- ExecutionContext *m_contextList;
public:
PersistentValuePrivate *m_persistentValues;
PersistentValuePrivate *m_weakValues;
};
-inline ExecutionContext *MemoryManager::allocContext(uint size)
-{
- ExecutionContext *newContext = (ExecutionContext *)malloc(size);
- newContext->next = m_contextList;
- m_contextList = newContext;
- return newContext;
-}
-
-
}
QT_END_NAMESPACE
diff --git a/src/qml/jsruntime/qv4object.cpp b/src/qml/jsruntime/qv4object.cpp
index cca7d2b26a..e4df95716d 100644
--- a/src/qml/jsruntime/qv4object.cpp
+++ b/src/qml/jsruntime/qv4object.cpp
@@ -1133,7 +1133,7 @@ ReturnedValue Object::arrayIndexOf(const ValueRef v, uint fromIndex, uint endInd
Scope scope(engine());
ScopedValue value(scope);
- if (!(flags & SimpleArray) || o->protoHasArray() || o->arrayAttributes) {
+ if (!(o->flags & SimpleArray) || o->protoHasArray()) {
// lets be safe and slow
for (uint i = fromIndex; i < endIndex; ++i) {
bool exists;
diff --git a/src/qml/jsruntime/qv4objectiterator.cpp b/src/qml/jsruntime/qv4objectiterator.cpp
index 62595b5176..04fa504991 100644
--- a/src/qml/jsruntime/qv4objectiterator.cpp
+++ b/src/qml/jsruntime/qv4objectiterator.cpp
@@ -42,6 +42,7 @@
#include "qv4object_p.h"
#include "qv4stringobject_p.h"
#include "qv4identifier_p.h"
+#include "qv4argumentsobject_p.h"
using namespace QV4;
@@ -56,6 +57,11 @@ ObjectIterator::ObjectIterator(SafeObject *scratch1, SafeObject *scratch2, const
object = o;
current = o;
tmpDynamicProperty.value = Primitive::undefinedValue();
+
+ if (object && object->isNonStrictArgumentsObject) {
+ Scope scope(object->engine());
+ Scoped<ArgumentsObject> (scope, object->asReturnedValue())->fullyCreate();
+ }
}
ObjectIterator::ObjectIterator(Scope &scope, const ObjectRef o, uint flags)
@@ -69,6 +75,11 @@ ObjectIterator::ObjectIterator(Scope &scope, const ObjectRef o, uint flags)
object = o;
current = o;
tmpDynamicProperty.value = Primitive::undefinedValue();
+
+ if (object && object->isNonStrictArgumentsObject) {
+ Scope scope(object->engine());
+ Scoped<ArgumentsObject> (scope, object->asReturnedValue())->fullyCreate();
+ }
}
Property *ObjectIterator::next(StringRef name, uint *index, PropertyAttributes *attrs)
diff --git a/src/qml/jsruntime/qv4objectproto.cpp b/src/qml/jsruntime/qv4objectproto.cpp
index 4369267278..f17bd7d5ba 100644
--- a/src/qml/jsruntime/qv4objectproto.cpp
+++ b/src/qml/jsruntime/qv4objectproto.cpp
@@ -41,6 +41,7 @@
#include "qv4objectproto_p.h"
+#include "qv4argumentsobject_p.h"
#include "qv4mm_p.h"
#include "qv4scopedvalue_p.h"
#include <QtCore/qnumeric.h>
@@ -156,6 +157,9 @@ ReturnedValue ObjectPrototype::method_getOwnPropertyDescriptor(CallContext *ctx)
if (!O)
return ctx->throwTypeError();
+ if (O->isNonStrictArgumentsObject)
+ Scoped<ArgumentsObject>(scope, O)->fullyCreate();
+
ScopedValue v(scope, ctx->argument(1));
Scoped<String> name(scope, v->toString(ctx));
if (scope.hasException())
@@ -283,6 +287,9 @@ ReturnedValue ObjectPrototype::method_freeze(CallContext *ctx)
if (!o)
return ctx->throwTypeError();
+ if (o->isNonStrictArgumentsObject)
+ Scoped<ArgumentsObject>(scope, o)->fullyCreate();
+
o->extensible = false;
o->internalClass = o->internalClass->frozen();
diff --git a/src/qml/jsruntime/qv4runtime.cpp b/src/qml/jsruntime/qv4runtime.cpp
index a8cabcb374..a5a93e1f84 100644
--- a/src/qml/jsruntime/qv4runtime.cpp
+++ b/src/qml/jsruntime/qv4runtime.cpp
@@ -966,10 +966,10 @@ ReturnedValue __qmljs_construct_value(ExecutionContext *context, const ValueRef
return f->construct(callData);
}
-ReturnedValue __qmljs_construct_property(ExecutionContext *context, const ValueRef base, const StringRef name, CallDataRef callData)
+ReturnedValue __qmljs_construct_property(ExecutionContext *context, const StringRef name, CallDataRef callData)
{
Scope scope(context);
- ScopedObject thisObject(scope, base->toObject(context));
+ ScopedObject thisObject(scope, callData->thisObject.toObject(context));
if (scope.engine->hasException)
return Encode::undefined();
@@ -980,6 +980,18 @@ ReturnedValue __qmljs_construct_property(ExecutionContext *context, const ValueR
return f->construct(callData);
}
+ReturnedValue __qmljs_construct_property_lookup(ExecutionContext *context, uint index, CallDataRef callData)
+{
+ Lookup *l = context->lookups + index;
+ SafeValue v;
+ v = l->getter(l, callData->thisObject);
+ if (!v.isManaged())
+ return context->throwTypeError();
+
+ return v.managed()->construct(callData);
+}
+
+
void __qmljs_throw(ExecutionContext *context, const ValueRef value)
{
if (!value->isEmpty())
@@ -1230,10 +1242,9 @@ ReturnedValue __qmljs_lookup_runtime_regexp(ExecutionContext *ctx, int id)
return ctx->compilationUnit->runtimeRegularExpressions[id].asReturnedValue();
}
-ReturnedValue __qmljs_get_id_object(NoThrowContext *ctx, int id)
+ReturnedValue __qmljs_get_id_array(NoThrowContext *ctx)
{
- QQmlContextData *context = QmlContextWrapper::callingContext(ctx->engine);
- return QObjectWrapper::wrap(ctx->engine, context->idValues[id].data());
+ return ctx->engine->qmlContextObject()->getPointer()->as<QmlContextWrapper>()->idObjectsArray();
}
ReturnedValue __qmljs_get_context_object(NoThrowContext *ctx)
@@ -1277,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 b5567693e5..da596b180c 100644
--- a/src/qml/jsruntime/qv4runtime_p.h
+++ b/src/qml/jsruntime/qv4runtime_p.h
@@ -125,7 +125,8 @@ QV4::ReturnedValue __qmljs_call_element(ExecutionContext *context, const ValueRe
QV4::ReturnedValue __qmljs_call_value(QV4::ExecutionContext *context, const QV4::ValueRef func, CallDataRef callData);
QV4::ReturnedValue __qmljs_construct_activation_property(QV4::ExecutionContext *, const QV4::StringRef name, CallDataRef callData);
-QV4::ReturnedValue __qmljs_construct_property(QV4::ExecutionContext *context, const QV4::ValueRef base, const QV4::StringRef name, CallDataRef callData);
+QV4::ReturnedValue __qmljs_construct_property(QV4::ExecutionContext *context, const QV4::StringRef name, CallDataRef callData);
+QV4::ReturnedValue __qmljs_construct_property_lookup(ExecutionContext *context, uint index, CallDataRef callData);
QV4::ReturnedValue __qmljs_construct_value(QV4::ExecutionContext *context, const QV4::ValueRef func, CallDataRef callData);
QV4::ReturnedValue __qmljs_builtin_typeof(QV4::ExecutionContext *ctx, const QV4::ValueRef val);
@@ -170,12 +171,13 @@ QV4::ReturnedValue __qmljs_construct_global_lookup(QV4::ExecutionContext *contex
QV4::ReturnedValue __qmljs_get_element(QV4::ExecutionContext *ctx, const QV4::ValueRef object, const QV4::ValueRef index);
void __qmljs_set_element(QV4::ExecutionContext *ctx, const QV4::ValueRef object, const QV4::ValueRef index, const QV4::ValueRef value);
-QV4::ReturnedValue __qmljs_get_id_object(NoThrowContext *ctx, int id);
+QV4::ReturnedValue __qmljs_get_id_array(NoThrowContext *ctx);
QV4::ReturnedValue __qmljs_get_imported_scripts(NoThrowContext *ctx);
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/qv4script.cpp b/src/qml/jsruntime/qv4script.cpp
index 25791cff61..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>
@@ -62,11 +63,18 @@ using namespace QV4;
QmlBindingWrapper::QmlBindingWrapper(ExecutionContext *scope, Function *f, ObjectRef qml)
: FunctionObject(scope, scope->engine->id_eval)
, qml(qml)
+ , qmlContext(0)
{
+ Q_ASSERT(scope->inUse);
+
vtbl = &static_vtbl;
function = f;
function->compilationUnit->ref();
needsActivation = function->needsActivation();
+
+ Scope s(scope);
+ ScopedValue protectThis(s, this);
+
defineReadonlyProperty(scope->engine->id_length, Primitive::fromInt32(1));
qmlContext = scope->engine->current->newQmlContext(this, qml);
@@ -76,10 +84,17 @@ QmlBindingWrapper::QmlBindingWrapper(ExecutionContext *scope, Function *f, Objec
QmlBindingWrapper::QmlBindingWrapper(ExecutionContext *scope, ObjectRef qml)
: FunctionObject(scope, scope->engine->id_eval)
, qml(qml)
+ , qmlContext(0)
{
+ Q_ASSERT(scope->inUse);
+
vtbl = &static_vtbl;
function = 0;
needsActivation = false;
+
+ Scope s(scope);
+ ScopedValue protectThis(s, this);
+
defineReadonlyProperty(scope->engine->id_length, Primitive::fromInt32(1));
qmlContext = scope->engine->current->newQmlContext(this, qml);
@@ -110,7 +125,8 @@ void QmlBindingWrapper::markObjects(Managed *m, ExecutionEngine *e)
if (wrapper->qml)
wrapper->qml->mark(e);
FunctionObject::markObjects(m, e);
- wrapper->qmlContext->mark();
+ if (wrapper->qmlContext)
+ wrapper->qmlContext->mark(e);
}
DEFINE_MANAGED_VTABLE(QmlBindingWrapper);
@@ -214,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();
@@ -340,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/jsruntime/qv4vme_moth.cpp b/src/qml/jsruntime/qv4vme_moth.cpp
index 72db469ee6..00672fea0f 100644
--- a/src/qml/jsruntime/qv4vme_moth.cpp
+++ b/src/qml/jsruntime/qv4vme_moth.cpp
@@ -503,10 +503,19 @@ QV4::ReturnedValue VME::run(QV4::ExecutionContext *context, const uchar *code,
QV4::CallData *callData = reinterpret_cast<QV4::CallData *>(stack + instr.callData);
callData->tag = QV4::Value::Integer_Type;
callData->argc = instr.argc;
- callData->thisObject = QV4::Primitive::undefinedValue();
- STOREVALUE(instr.result, __qmljs_construct_property(context, VALUEPTR(instr.base), runtimeStrings[instr.name], callData));
+ callData->thisObject = VALUE(instr.base);
+ STOREVALUE(instr.result, __qmljs_construct_property(context, runtimeStrings[instr.name], callData));
MOTH_END_INSTR(CreateProperty)
+ MOTH_BEGIN_INSTR(ConstructPropertyLookup)
+ Q_ASSERT(instr.callData + instr.argc + qOffsetOf(QV4::CallData, args)/sizeof(QV4::SafeValue) <= stackSize);
+ QV4::CallData *callData = reinterpret_cast<QV4::CallData *>(stack + instr.callData);
+ callData->tag = QV4::Value::Integer_Type;
+ callData->argc = instr.argc;
+ callData->thisObject = VALUE(instr.base);
+ STOREVALUE(instr.result, __qmljs_construct_property_lookup(context, instr.index, callData));
+ MOTH_END_INSTR(ConstructPropertyLookup)
+
MOTH_BEGIN_INSTR(CreateActivationProperty)
TRACE(inline, "property name = %s, args = %d, argc = %d", runtimeStrings[instr.name]->toQString().toUtf8().constData(), instr.args, instr.argc);
Q_ASSERT(instr.callData + instr.argc + qOffsetOf(QV4::CallData, args)/sizeof(QV4::SafeValue) <= stackSize);
@@ -648,9 +657,9 @@ QV4::ReturnedValue VME::run(QV4::ExecutionContext *context, const uchar *code,
VALUE(instr.result) = context->callData->thisObject;
MOTH_END_INSTR(LoadThis)
- MOTH_BEGIN_INSTR(LoadQmlIdObject)
- VALUE(instr.result) = __qmljs_get_id_object(static_cast<QV4::NoThrowContext*>(context), instr.id);
- MOTH_END_INSTR(LoadQmlIdObject)
+ MOTH_BEGIN_INSTR(LoadQmlIdArray)
+ VALUE(instr.result) = __qmljs_get_id_array(static_cast<QV4::NoThrowContext*>(context));
+ MOTH_END_INSTR(LoadQmlIdArray)
MOTH_BEGIN_INSTR(LoadQmlImportedScripts)
VALUE(instr.result) = __qmljs_get_imported_scripts(static_cast<QV4::NoThrowContext*>(context));
@@ -664,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/qqmlcompiler.cpp b/src/qml/qml/qqmlcompiler.cpp
index 93ec2516c8..54fd002f7b 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/qqmlcontextwrapper.cpp b/src/qml/qml/qqmlcontextwrapper.cpp
index 406826a6f6..0b3b282061 100644
--- a/src/qml/qml/qqmlcontextwrapper.cpp
+++ b/src/qml/qml/qqmlcontextwrapper.cpp
@@ -63,7 +63,7 @@ DEFINE_MANAGED_VTABLE(QmlContextWrapper);
QmlContextWrapper::QmlContextWrapper(QV8Engine *engine, QQmlContextData *context, QObject *scopeObject, bool ownsContext)
: Object(QV8Engine::getV4(engine)),
v8(engine), readOnly(true), ownsContext(ownsContext), isNullWrapper(false),
- context(context), scopeObject(scopeObject)
+ context(context), scopeObject(scopeObject), idObjectsWrapper(0)
{
vtbl = &static_vtbl;
}
@@ -355,6 +355,14 @@ void QmlContextWrapper::destroy(Managed *that)
static_cast<QmlContextWrapper *>(that)->~QmlContextWrapper();
}
+void QmlContextWrapper::markObjects(Managed *m, ExecutionEngine *engine)
+{
+ QmlContextWrapper *This = static_cast<QmlContextWrapper*>(m);
+ if (This->idObjectsWrapper)
+ This->idObjectsWrapper->mark(engine);
+ Object::markObjects(m, engine);
+}
+
void QmlContextWrapper::registerQmlDependencies(ExecutionEngine *engine, const CompiledData::Function *compiledFunction)
{
// Let the caller check and avoid the function call :)
@@ -395,4 +403,71 @@ void QmlContextWrapper::registerQmlDependencies(ExecutionEngine *engine, const C
}
+ReturnedValue QmlContextWrapper::idObjectsArray()
+{
+ if (!idObjectsWrapper) {
+ ExecutionEngine *v4 = engine();
+ idObjectsWrapper = new (v4->memoryManager) QQmlIdObjectsArray(v4, this);
+ }
+ 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)
+ : Object(engine)
+ , contextWrapper(contextWrapper)
+{
+ vtbl = &static_vtbl;
+}
+
+ReturnedValue QQmlIdObjectsArray::getIndexed(Managed *m, uint index, bool *hasProperty)
+{
+ QQmlIdObjectsArray *This = static_cast<QQmlIdObjectsArray*>(m);
+ QQmlContextData *context = This->contextWrapper->getContext();
+ if (!context) {
+ if (hasProperty)
+ *hasProperty = false;
+ return Encode::undefined();
+ }
+ if (index >= (uint)context->idValueCount) {
+ if (hasProperty)
+ *hasProperty = false;
+ return Encode::undefined();
+ }
+
+ ExecutionEngine *v4 = m->engine();
+ QQmlEnginePrivate *ep = v4->v8Engine->engine() ? QQmlEnginePrivate::get(v4->v8Engine->engine()) : 0;
+ if (ep)
+ ep->captureProperty(&context->idValues[index].bindings);
+
+ return QObjectWrapper::wrap(This->engine(), context->idValues[index].data());
+}
+
+void QQmlIdObjectsArray::markObjects(Managed *that, ExecutionEngine *engine)
+{
+ QQmlIdObjectsArray *This = static_cast<QQmlIdObjectsArray*>(that);
+ This->contextWrapper->mark(engine);
+ Object::markObjects(that, engine);
+}
+
QT_END_NAMESPACE
diff --git a/src/qml/qml/qqmlcontextwrapper_p.h b/src/qml/qml/qqmlcontextwrapper_p.h
index d85f440b15..89ace7090c 100644
--- a/src/qml/qml/qqmlcontextwrapper_p.h
+++ b/src/qml/qml/qqmlcontextwrapper_p.h
@@ -69,6 +69,8 @@ namespace CompiledData {
struct Function;
}
+struct QQmlIdObjectsArray;
+
struct Q_QML_EXPORT QmlContextWrapper : Object
{
Q_MANAGED
@@ -90,9 +92,12 @@ struct Q_QML_EXPORT QmlContextWrapper : Object
static ReturnedValue get(Managed *m, const StringRef name, bool *hasProperty);
static void put(Managed *m, const StringRef name, const ValueRef value);
static void destroy(Managed *that);
+ static void markObjects(Managed *m, ExecutionEngine *engine);
static void registerQmlDependencies(ExecutionEngine *context, const CompiledData::Function *compiledFunction);
+ ReturnedValue idObjectsArray();
+ ReturnedValue qmlSingletonWrapper(const StringRef &name);
QV8Engine *v8; // ### temporary, remove
bool readOnly;
@@ -101,6 +106,19 @@ struct Q_QML_EXPORT QmlContextWrapper : Object
QQmlGuardedContextData context;
QPointer<QObject> scopeObject;
+private:
+ QQmlIdObjectsArray *idObjectsWrapper;
+};
+
+struct QQmlIdObjectsArray : public Object
+{
+ Q_MANAGED
+ QQmlIdObjectsArray(ExecutionEngine *engine, QmlContextWrapper *contextWrapper);
+
+ static ReturnedValue getIndexed(Managed *m, uint index, bool *hasProperty);
+ static void markObjects(Managed *that, ExecutionEngine *engine);
+
+ QmlContextWrapper *contextWrapper;
};
}
diff --git a/src/qml/qml/qqmlengine.cpp b/src/qml/qml/qqmlengine.cpp
index d082b9a8fd..1eec710c84 100644
--- a/src/qml/qml/qqmlengine.cpp
+++ b/src/qml/qml/qqmlengine.cpp
@@ -556,7 +556,7 @@ QQmlEnginePrivate::QQmlEnginePrivate(QQmlEngine *e)
workerScriptEngine(0), activeVME(0),
activeObjectCreator(0),
networkAccessManager(0), networkAccessManagerFactory(0), urlInterceptor(0),
- scarceResourcesRefCount(0), typeLoader(e), importDatabase(e), uniqueId(1),
+ scarceResourcesRefCount(0), importDatabase(e), typeLoader(e), uniqueId(1),
incubatorCount(0), incubationController(0), mutex(QMutex::Recursive)
{
useNewCompiler = qmlUseNewCompiler();
diff --git a/src/qml/qml/qqmlengine_p.h b/src/qml/qml/qqmlengine_p.h
index 5a2d6c4e00..19eb320fbe 100644
--- a/src/qml/qml/qqmlengine_p.h
+++ b/src/qml/qml/qqmlengine_p.h
@@ -186,8 +186,8 @@ public:
void referenceScarceResources();
void dereferenceScarceResources();
- QQmlTypeLoader typeLoader;
QQmlImportDatabase importDatabase;
+ QQmlTypeLoader typeLoader;
QString offlineStoragePath;
@@ -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/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)
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);
diff --git a/src/qml/util/qqmladaptormodel.cpp b/src/qml/util/qqmladaptormodel.cpp
index 9cd5709a49..38fdffdde6 100644
--- a/src/qml/util/qqmladaptormodel.cpp
+++ b/src/qml/util/qqmladaptormodel.cpp
@@ -902,7 +902,7 @@ void QQmlAdaptorModel::setModel(const QVariant &variant, QQmlDelegateModel *vdm,
list.setList(variant, engine);
- if (QObject *object = qvariant_cast<QObject *>(variant)) {
+ if (QObject *object = qvariant_cast<QObject *>(list.list())) {
setObject(object);
if (QAbstractItemModel *model = qobject_cast<QAbstractItemModel *>(object)) {
accessors = new VDMAbstractItemModelDataType(this);
@@ -927,8 +927,8 @@ void QQmlAdaptorModel::setModel(const QVariant &variant, QQmlDelegateModel *vdm,
} else if (list.type() == QQmlListAccessor::ListProperty) {
setObject(static_cast<const QQmlListReference *>(variant.constData())->object());
accessors = new VDMObjectDelegateDataType;
- } else if (list.type() != QQmlListAccessor::Invalid) {
- Q_ASSERT(list.type() != QQmlListAccessor::Instance); // Should have cast to QObject.
+ } else if (list.type() != QQmlListAccessor::Invalid
+ && list.type() != QQmlListAccessor::Instance) { // Null QObject
setObject(0);
accessors = &qt_vdm_list_accessors;
} else {
diff --git a/src/quick/doc/src/concepts/visualcanvas/scenegraph.qdoc b/src/quick/doc/src/concepts/visualcanvas/scenegraph.qdoc
index 384e8209c1..16075f0db3 100644
--- a/src/quick/doc/src/concepts/visualcanvas/scenegraph.qdoc
+++ b/src/quick/doc/src/concepts/visualcanvas/scenegraph.qdoc
@@ -724,6 +724,11 @@ with multiple windows.
\li Some material flags prevent batching, the most limiting one
being QSGMaterial::RequiresFullMatrix which prevents all batching.
+ \li Applications with a monochrome background should set it using
+ QQuickWindow::setColor() rather than using a top-level Rectangle item.
+ QQuickWindow::setColor() will be used in a call to \c glClear(),
+ which is potentially faster.
+
\endlist
If an application performs poorly, make sure that rendering is
diff --git a/src/quick/items/qquickflickable.cpp b/src/quick/items/qquickflickable.cpp
index f0a68b184a..ae174d86e0 100644
--- a/src/quick/items/qquickflickable.cpp
+++ b/src/quick/items/qquickflickable.cpp
@@ -1116,10 +1116,10 @@ void QQuickFlickablePrivate::handleMouseMoveEvent(QMouseEvent *event)
hData.velocity = 0;
}
- if ((hMoved && !prevHMoved) || (vMoved && !prevVMoved)) {
- draggingStarting();
+ draggingStarting();
+
+ if ((hMoved && !prevHMoved) || (vMoved && !prevVMoved))
q->movementStarting();
- }
qint64 currentTimestamp = computeCurrentTime(event);
qreal elapsed = qreal(currentTimestamp - (lastPos.isNull() ? lastPressTime : lastPosTime)) / 1000.;
diff --git a/src/quick/items/qquickitemview.cpp b/src/quick/items/qquickitemview.cpp
index 513f8f3857..d9ff024d9f 100644
--- a/src/quick/items/qquickitemview.cpp
+++ b/src/quick/items/qquickitemview.cpp
@@ -1118,11 +1118,13 @@ void QQuickItemViewPrivate::itemGeometryChanged(QQuickItem *item, const QRectF &
if (header && header->item == item) {
updateHeader();
markExtentsDirty();
+ updateViewport();
if (!q->isMoving() && !q->isFlicking())
fixupPosition();
} else if (footer && footer->item == item) {
updateFooter();
markExtentsDirty();
+ updateViewport();
if (!q->isMoving() && !q->isFlicking())
fixupPosition();
}
diff --git a/src/quick/items/qquickshadereffect.cpp b/src/quick/items/qquickshadereffect.cpp
index 9c766a1622..9a20703f18 100644
--- a/src/quick/items/qquickshadereffect.cpp
+++ b/src/quick/items/qquickshadereffect.cpp
@@ -559,6 +559,7 @@ void QQuickShaderEffectCommon::propertyChanged(QQuickItem *item, int mappedId,
\li QVector4D -> vec4
\li QTransform -> mat3
\li QMatrix4x4 -> mat4
+ \li QQuaternion -> vec4, scalar value is \c w.
\li \l Image, \l ShaderEffectSource -> sampler2D - Origin is in the top-left
corner, and the color values are premultiplied.
\endlist
diff --git a/src/quick/items/qquickshadereffectnode.cpp b/src/quick/items/qquickshadereffectnode.cpp
index 8788fa8362..3ab13dbbc7 100644
--- a/src/quick/items/qquickshadereffectnode.cpp
+++ b/src/quick/items/qquickshadereffectnode.cpp
@@ -197,6 +197,12 @@ void QQuickCustomMaterialShader::updateState(const RenderState &state, QSGMateri
case QMetaType::QVector4D:
program()->setUniformValue(loc, qvariant_cast<QVector4D>(d.value));
break;
+ case QMetaType::QQuaternion:
+ {
+ QQuaternion q = qvariant_cast<QQuaternion>(d.value);
+ program()->setUniformValue(loc, q.x(), q.y(), q.z(), q.scalar());
+ }
+ break;
case QMetaType::QMatrix4x4:
program()->setUniformValue(loc, qvariant_cast<QMatrix4x4>(d.value));
break;
diff --git a/src/quick/items/qquickwindow.cpp b/src/quick/items/qquickwindow.cpp
index 848eeca2a6..3a8e177bbb 100644
--- a/src/quick/items/qquickwindow.cpp
+++ b/src/quick/items/qquickwindow.cpp
@@ -665,14 +665,18 @@ void QQuickWindowPrivate::setFocusInScope(QQuickItem *scope, QQuickItem *item, Q
QVarLengthArray<QQuickItem *, 20> changed;
// Does this change the active focus?
- if (item == contentItem || (scopePrivate->activeFocus && item->isEnabled())) {
+ if (item == contentItem || scopePrivate->activeFocus) {
QQuickItem *oldActiveFocusItem = 0;
oldActiveFocusItem = activeFocusItem;
- newActiveFocusItem = item;
- while (newActiveFocusItem->isFocusScope()
- && newActiveFocusItem->scopedFocusItem()
- && newActiveFocusItem->scopedFocusItem()->isEnabled()) {
- newActiveFocusItem = newActiveFocusItem->scopedFocusItem();
+ if (item->isEnabled()) {
+ newActiveFocusItem = item;
+ while (newActiveFocusItem->isFocusScope()
+ && newActiveFocusItem->scopedFocusItem()
+ && newActiveFocusItem->scopedFocusItem()->isEnabled()) {
+ newActiveFocusItem = newActiveFocusItem->scopedFocusItem();
+ }
+ } else {
+ newActiveFocusItem = scope;
}
if (oldActiveFocusItem) {
@@ -2795,6 +2799,7 @@ QImage QQuickWindow::grabWindow()
QOpenGLContext context;
context.setFormat(requestedFormat());
+ context.setShareContext(QSGContext::sharedOpenGLContext());
context.create();
context.makeCurrent(this);
d->context->initialize(&context);
diff --git a/src/quick/scenegraph/qsgrenderloop.cpp b/src/quick/scenegraph/qsgrenderloop.cpp
index 9c39ef65f9..aa0d7b5a6c 100644
--- a/src/quick/scenegraph/qsgrenderloop.cpp
+++ b/src/quick/scenegraph/qsgrenderloop.cpp
@@ -277,6 +277,7 @@ void QSGGuiThreadRenderLoop::renderWindow(QQuickWindow *window)
if (QSGContext::sharedOpenGLContext())
gl->setShareContext(QSGContext::sharedOpenGLContext());
if (!gl->create()) {
+ qWarning("QtQuick: failed to create OpenGL context");
delete gl;
gl = 0;
} else {
diff --git a/src/quick/scenegraph/qsgwindowsrenderloop.cpp b/src/quick/scenegraph/qsgwindowsrenderloop.cpp
index 03ee4992bc..0c128d5cae 100644
--- a/src/quick/scenegraph/qsgwindowsrenderloop.cpp
+++ b/src/quick/scenegraph/qsgwindowsrenderloop.cpp
@@ -180,13 +180,20 @@ void QSGWindowsRenderLoop::show(QQuickWindow *window)
m_gl->setFormat(window->requestedFormat());
if (QSGContext::sharedOpenGLContext())
m_gl->setShareContext(QSGContext::sharedOpenGLContext());
- m_gl->create();
+ bool created = m_gl->create();
+ if (!created) {
+ qWarning("QtQuick: failed to create OpenGL context");
+ delete m_gl;
+ m_gl = 0;
+ return;
+ }
QSG_RENDER_TIMING_SAMPLE(time_created);
RLDEBUG(" - making current");
- m_gl->makeCurrent(window);
+ bool current = m_gl->makeCurrent(window);
RLDEBUG(" - initializing SG");
QSG_RENDER_TIMING_SAMPLE(time_current);
- QQuickWindowPrivate::get(window)->context->initialize(m_gl);
+ if (current)
+ m_rc->initialize(m_gl);
#ifndef QSG_NO_RENDER_TIMING
if (qsg_render_timing) {
diff --git a/src/quick/util/qquicksmoothedanimation.cpp b/src/quick/util/qquicksmoothedanimation.cpp
index 017fe39003..9e9e6cb419 100644
--- a/src/quick/util/qquicksmoothedanimation.cpp
+++ b/src/quick/util/qquicksmoothedanimation.cpp
@@ -242,6 +242,9 @@ qreal QSmoothedAnimation::easeFollow(qreal time_seconds)
void QSmoothedAnimation::updateCurrentTime(int t)
{
+ if (!isRunning() && !isPaused()) // This can happen if init() stops the animation in some cases
+ return;
+
qreal time_seconds = useDelta ? qreal(QQmlAnimationTimer::instance()->currentDelta()) / 1000. : qreal(t - lastTime) / 1000.;
if (useDelta)
useDelta = false;
diff --git a/tests/auto/qml/animation/qpauseanimationjob/tst_qpauseanimationjob.cpp b/tests/auto/qml/animation/qpauseanimationjob/tst_qpauseanimationjob.cpp
index a832c58ae3..5a1148e92e 100644
--- a/tests/auto/qml/animation/qpauseanimationjob/tst_qpauseanimationjob.cpp
+++ b/tests/auto/qml/animation/qpauseanimationjob/tst_qpauseanimationjob.cpp
@@ -211,19 +211,8 @@ void tst_QPauseAnimationJob::multiplePauseAnimations()
#endif
QCOMPARE(animation2.m_updateCurrentTimeCount, 2);
- QTest::qWait(550);
-
-#ifdef Q_OS_WIN
- if (animation2.state() != QAbstractAnimationJob::Stopped)
- QEXPECT_FAIL("", winTimerError, Abort);
-#endif
- QVERIFY(animation2.state() == QAbstractAnimationJob::Stopped);
-
-#ifdef Q_OS_WIN
- if (animation2.m_updateCurrentTimeCount != 3)
- QEXPECT_FAIL("", winTimerError, Abort);
-#endif
- QCOMPARE(animation2.m_updateCurrentTimeCount, 3);
+ QTRY_COMPARE(animation2.state(), QAbstractAnimationJob::Stopped);
+ QVERIFY(animation2.m_updateCurrentTimeCount >= 3);
}
void tst_QPauseAnimationJob::pauseAndPropertyAnimations()
@@ -240,19 +229,17 @@ void tst_QPauseAnimationJob::pauseAndPropertyAnimations()
QTest::qWait(100);
animation.start();
- QVERIFY(animation.state() == QAbstractAnimationJob::Running);
- QVERIFY(pause.state() == QAbstractAnimationJob::Running);
- QCOMPARE(pause.m_updateCurrentTimeCount, 2);
+ QCOMPARE(animation.state(), QAbstractAnimationJob::Running);
- QTest::qWait(animation.totalDuration() + 100);
+ QTRY_COMPARE(animation.state(), QAbstractAnimationJob::Running);
+ QVERIFY(pause.state() == QAbstractAnimationJob::Running);
+ QVERIFY2(pause.m_updateCurrentTimeCount >= 2,
+ QByteArrayLiteral("pause.m_updateCurrentTimeCount=") + QByteArray::number(pause.m_updateCurrentTimeCount));
-#ifdef Q_OS_WIN
- if (animation.state() != QAbstractAnimationJob::Stopped)
- QEXPECT_FAIL("", winTimerError, Abort);
-#endif
- QVERIFY(animation.state() == QAbstractAnimationJob::Stopped);
- QVERIFY(pause.state() == QAbstractAnimationJob::Stopped);
- QVERIFY(pause.m_updateCurrentTimeCount > 3);
+ QTRY_COMPARE(animation.state(), QAbstractAnimationJob::Stopped);
+ QCOMPARE(pause.state(), QAbstractAnimationJob::Stopped);
+ QVERIFY2(pause.m_updateCurrentTimeCount > 3,
+ QByteArrayLiteral("pause.m_updateCurrentTimeCount=") + QByteArray::number(pause.m_updateCurrentTimeCount));
}
void tst_QPauseAnimationJob::pauseResume()
@@ -260,19 +247,15 @@ void tst_QPauseAnimationJob::pauseResume()
TestablePauseAnimation animation;
animation.setDuration(400);
animation.start();
- QVERIFY(animation.state() == QAbstractAnimationJob::Running);
+ QCOMPARE(animation.state(), QAbstractAnimationJob::Running);
QTest::qWait(200);
animation.pause();
- QVERIFY(animation.state() == QAbstractAnimationJob::Paused);
+ QCOMPARE(animation.state(), QAbstractAnimationJob::Paused);
animation.start();
QTest::qWait(300);
- QVERIFY(animation.state() == QAbstractAnimationJob::Stopped);
-
-#ifdef Q_OS_WIN
- if (animation.m_updateCurrentTimeCount != 3)
- QEXPECT_FAIL("", winTimerError, Abort);
-#endif
- QCOMPARE(animation.m_updateCurrentTimeCount, 3);
+ QTRY_VERIFY(animation.state() == QAbstractAnimationJob::Stopped);
+ QVERIFY2(animation.m_updateCurrentTimeCount >= 3,
+ QByteArrayLiteral("animation.m_updateCurrentTimeCount=") + QByteArray::number(animation.m_updateCurrentTimeCount));
}
void tst_QPauseAnimationJob::sequentialPauseGroup()
@@ -423,7 +406,7 @@ void tst_QPauseAnimationJob::multipleSequentialGroups()
if (group.state() != QAbstractAnimationJob::Stopped)
QEXPECT_FAIL("", winTimerError, Abort);
#endif
- QVERIFY(group.state() == QAbstractAnimationJob::Stopped);
+ QTRY_VERIFY(group.state() == QAbstractAnimationJob::Stopped);
#ifdef Q_OS_WIN
if (subgroup1.state() != QAbstractAnimationJob::Stopped)
diff --git a/tests/auto/qml/debugger/shared/qqmldebugclient.cpp b/tests/auto/qml/debugger/shared/qqmldebugclient.cpp
index 95674ce6d7..6474a04796 100644
--- a/tests/auto/qml/debugger/shared/qqmldebugclient.cpp
+++ b/tests/auto/qml/debugger/shared/qqmldebugclient.cpp
@@ -449,6 +449,7 @@ QString QQmlDebugClient::stateString() const
case Unavailable: return QLatin1String("Unavailable");
case Enabled: return QLatin1String("Enabled");
}
+ return QLatin1String("Invalid");
}
void QQmlDebugClient::sendMessage(const QByteArray &message)
diff --git a/tests/auto/qml/qqmlxmlhttprequest/tst_qqmlxmlhttprequest.cpp b/tests/auto/qml/qqmlxmlhttprequest/tst_qqmlxmlhttprequest.cpp
index 3ae27fe9c3..9c67e6e2e9 100644
--- a/tests/auto/qml/qqmlxmlhttprequest/tst_qqmlxmlhttprequest.cpp
+++ b/tests/auto/qml/qqmlxmlhttprequest/tst_qqmlxmlhttprequest.cpp
@@ -127,8 +127,8 @@ private:
void tst_qqmlxmlhttprequest::domExceptionCodes()
{
QQmlComponent component(&engine, testFileUrl("domExceptionCodes.qml"));
- QObject *object = component.create();
- QVERIFY(object != 0);
+ QScopedPointer<QObject> object(component.create());
+ QVERIFY(!object.isNull());
QCOMPARE(object->property("index_size_err").toInt(), 1);
QCOMPARE(object->property("domstring_size_err").toInt(), 2);
@@ -147,8 +147,6 @@ void tst_qqmlxmlhttprequest::domExceptionCodes()
QCOMPARE(object->property("invalid_access_err").toInt(), 15);
QCOMPARE(object->property("validation_err").toInt(), 16);
QCOMPARE(object->property("type_mismatch_err").toInt(), 17);
-
- delete object;
}
void tst_qqmlxmlhttprequest::callbackException_data()
@@ -172,15 +170,13 @@ void tst_qqmlxmlhttprequest::callbackException()
QTest::ignoreMessage(QtWarningMsg, expect.toLatin1());
QQmlComponent component(&engine, testFileUrl("callbackException.qml"));
- QObject *object = component.beginCreate(engine.rootContext());
- QVERIFY(object != 0);
+ QScopedPointer<QObject> object(component.beginCreate(engine.rootContext()));
+ QVERIFY(!object.isNull());
object->setProperty("url", "testdocument.html");
object->setProperty("which", which);
component.completeCreate();
QTRY_VERIFY(object->property("threw").toBool() == true);
-
- delete object;
}
// Test that the state value properties on the XMLHttpRequest constructor have the correct values.
@@ -188,61 +184,53 @@ void tst_qqmlxmlhttprequest::callbackException()
void tst_qqmlxmlhttprequest::staticStateValues()
{
QQmlComponent component(&engine, testFileUrl("staticStateValues.qml"));
- QObject *object = component.create();
- QVERIFY(object != 0);
+ QScopedPointer<QObject> object(component.create());
+ QVERIFY(!object.isNull());
QCOMPARE(object->property("unsent").toInt(), 0);
QCOMPARE(object->property("opened").toInt(), 1);
QCOMPARE(object->property("headers_received").toInt(), 2);
QCOMPARE(object->property("loading").toInt(), 3);
QCOMPARE(object->property("done").toInt(), 4);
-
- delete object;
}
// Test that the state value properties on instances have the correct values.
void tst_qqmlxmlhttprequest::instanceStateValues()
{
QQmlComponent component(&engine, testFileUrl("instanceStateValues.qml"));
- QObject *object = component.create();
- QVERIFY(object != 0);
+ QScopedPointer<QObject> object(component.create());
+ QVERIFY(!object.isNull());
QCOMPARE(object->property("unsent").toInt(), 0);
QCOMPARE(object->property("opened").toInt(), 1);
QCOMPARE(object->property("headers_received").toInt(), 2);
QCOMPARE(object->property("loading").toInt(), 3);
QCOMPARE(object->property("done").toInt(), 4);
-
- delete object;
}
// Test calling constructor
void tst_qqmlxmlhttprequest::constructor()
{
QQmlComponent component(&engine, testFileUrl("constructor.qml"));
- QObject *object = component.create();
- QVERIFY(object != 0);
+ QScopedPointer<QObject> object(component.create());
+ QVERIFY(!object.isNull());
QCOMPARE(object->property("calledAsConstructor").toBool(), true);
QCOMPARE(object->property("calledAsFunction").toBool(), true);
-
- delete object;
}
// Test that all the properties are set correctly before any request is sent
void tst_qqmlxmlhttprequest::defaultState()
{
QQmlComponent component(&engine, testFileUrl("defaultState.qml"));
- QObject *object = component.create();
- QVERIFY(object != 0);
+ QScopedPointer<QObject> object(component.create());
+ QVERIFY(!object.isNull());
QCOMPARE(object->property("readState").toInt(), 0);
QCOMPARE(object->property("statusIsException").toBool(), true);
QCOMPARE(object->property("statusTextIsException").toBool(), true);
QCOMPARE(object->property("responseText").toString(), QString());
QCOMPARE(object->property("responseXMLIsNull").toBool(), true);
-
- delete object;
}
// Test valid XMLHttpRequest.open() calls
@@ -262,8 +250,8 @@ void tst_qqmlxmlhttprequest::open()
}
QQmlComponent component(&engine, qmlFile);
- QObject *object = component.beginCreate(engine.rootContext());
- QVERIFY(object != 0);
+ QScopedPointer<QObject> object(component.beginCreate(engine.rootContext()));
+ QVERIFY(!object.isNull());
object->setProperty("url", url);
component.completeCreate();
@@ -275,8 +263,6 @@ void tst_qqmlxmlhttprequest::open()
QCOMPARE(object->property("responseXML").toBool(), true);
QTRY_VERIFY(object->property("dataOK").toBool() == true);
-
- delete object;
}
void tst_qqmlxmlhttprequest::open_data()
@@ -297,24 +283,20 @@ void tst_qqmlxmlhttprequest::open_data()
void tst_qqmlxmlhttprequest::open_invalid_method()
{
QQmlComponent component(&engine, testFileUrl("open_invalid_method.qml"));
- QObject *object = component.create();
- QVERIFY(object != 0);
+ QScopedPointer<QObject> object(component.create());
+ QVERIFY(!object.isNull());
QCOMPARE(object->property("exceptionThrown").toBool(), true);
-
- delete object;
}
// Test that calling XMLHttpRequest.open() with sync raises an exception
void tst_qqmlxmlhttprequest::open_sync()
{
QQmlComponent component(&engine, testFileUrl("open_sync.qml"));
- QObject *object = component.create();
- QVERIFY(object != 0);
+ QScopedPointer<QObject> object(component.create());
+ QVERIFY(!object.isNull());
QCOMPARE(object->property("exceptionThrown").toBool(), true);
-
- delete object;
}
// Calling with incorrect arg count raises an exception
@@ -322,22 +304,18 @@ void tst_qqmlxmlhttprequest::open_arg_count()
{
{
QQmlComponent component(&engine, testFileUrl("open_arg_count.1.qml"));
- QObject *object = component.create();
- QVERIFY(object != 0);
+ QScopedPointer<QObject> object(component.create());
+ QVERIFY(!object.isNull());
QCOMPARE(object->property("exceptionThrown").toBool(), true);
-
- delete object;
}
{
QQmlComponent component(&engine, testFileUrl("open_arg_count.2.qml"));
- QObject *object = component.create();
- QVERIFY(object != 0);
+ QScopedPointer<QObject> object(component.create());
+ QVERIFY(!object.isNull());
QCOMPARE(object->property("exceptionThrown").toBool(), true);
-
- delete object;
}
}
@@ -351,14 +329,12 @@ void tst_qqmlxmlhttprequest::setRequestHeader()
testFileUrl("testdocument.html")));
QQmlComponent component(&engine, testFileUrl("setRequestHeader.qml"));
- QObject *object = component.beginCreate(engine.rootContext());
- QVERIFY(object != 0);
+ QScopedPointer<QObject> object(component.beginCreate(engine.rootContext()));
+ QVERIFY(!object.isNull());
object->setProperty("url", "http://127.0.0.1:14445/testdocument.html");
component.completeCreate();
QTRY_VERIFY(object->property("dataOK").toBool() == true);
-
- delete object;
}
// Test valid setRequestHeader() calls with different header cases
@@ -371,25 +347,21 @@ void tst_qqmlxmlhttprequest::setRequestHeader_caseInsensitive()
testFileUrl("testdocument.html")));
QQmlComponent component(&engine, testFileUrl("setRequestHeader_caseInsensitive.qml"));
- QObject *object = component.beginCreate(engine.rootContext());
- QVERIFY(object != 0);
+ QScopedPointer<QObject> object(component.beginCreate(engine.rootContext()));
+ QVERIFY(!object.isNull());
object->setProperty("url", "http://127.0.0.1:14445/testdocument.html");
component.completeCreate();
QTRY_VERIFY(object->property("dataOK").toBool() == true);
-
- delete object;
}
// Test setting headers before open() throws exception
void tst_qqmlxmlhttprequest::setRequestHeader_unsent()
{
QQmlComponent component(&engine, testFileUrl("setRequestHeader_unsent.qml"));
- QObject *object = component.create();
- QVERIFY(object != 0);
+ QScopedPointer<QObject> object(component.create());
+ QVERIFY(!object.isNull());
QCOMPARE(object->property("test").toBool(), true);
-
- delete object;
}
void tst_qqmlxmlhttprequest::setRequestHeader_illegalName_data()
@@ -432,8 +404,8 @@ void tst_qqmlxmlhttprequest::setRequestHeader_illegalName()
testFileUrl("testdocument.html")));
QQmlComponent component(&engine, testFileUrl("setRequestHeader_illegalName.qml"));
- QObject *object = component.beginCreate(engine.rootContext());
- QVERIFY(object != 0);
+ QScopedPointer<QObject> object(component.beginCreate(engine.rootContext()));
+ QVERIFY(!object.isNull());
object->setProperty("url", "http://127.0.0.1:14445/testdocument.html");
object->setProperty("header", name);
component.completeCreate();
@@ -446,8 +418,6 @@ void tst_qqmlxmlhttprequest::setRequestHeader_illegalName()
QCOMPARE(object->property("responseXML").toBool(), true);
QTRY_VERIFY(object->property("dataOK").toBool() == true);
-
- delete object;
}
// Test that attempting to set a header after a request is sent throws an exception
@@ -460,53 +430,45 @@ void tst_qqmlxmlhttprequest::setRequestHeader_sent()
testFileUrl("testdocument.html")));
QQmlComponent component(&engine, testFileUrl("setRequestHeader_sent.qml"));
- QObject *object = component.beginCreate(engine.rootContext());
- QVERIFY(object != 0);
+ QScopedPointer<QObject> object(component.beginCreate(engine.rootContext()));
+ QVERIFY(!object.isNull());
object->setProperty("url", "http://127.0.0.1:14445/testdocument.html");
component.completeCreate();
QCOMPARE(object->property("test").toBool(), true);
QTRY_VERIFY(object->property("dataOK").toBool() == true);
-
- delete object;
}
// Invalid arg count throws exception
void tst_qqmlxmlhttprequest::setRequestHeader_args()
{
QQmlComponent component(&engine, testFileUrl("setRequestHeader_args.qml"));
- QObject *object = component.create();
- QVERIFY(object != 0);
+ QScopedPointer<QObject> object(component.create());
+ QVERIFY(!object.isNull());
QCOMPARE(object->property("exceptionThrown").toBool(), true);
-
- delete object;
}
// Test that calling send() in UNSENT state throws an exception
void tst_qqmlxmlhttprequest::send_unsent()
{
QQmlComponent component(&engine, testFileUrl("send_unsent.qml"));
- QObject *object = component.create();
- QVERIFY(object != 0);
+ QScopedPointer<QObject> object(component.create());
+ QVERIFY(!object.isNull());
QCOMPARE(object->property("test").toBool(), true);
-
- delete object;
}
// Test attempting to resend a sent request throws an exception
void tst_qqmlxmlhttprequest::send_alreadySent()
{
QQmlComponent component(&engine, testFileUrl("send_alreadySent.qml"));
- QObject *object = component.create();
- QVERIFY(object != 0);
+ QScopedPointer<QObject> object(component.create());
+ QVERIFY(!object.isNull());
QCOMPARE(object->property("test").toBool(), true);
QTRY_VERIFY(object->property("dataOK").toBool() == true);
-
- delete object;
}
// Test that sends for GET, HEAD and DELETE ignore data
@@ -520,15 +482,13 @@ void tst_qqmlxmlhttprequest::send_ignoreData()
testFileUrl("testdocument.html")));
QQmlComponent component(&engine, testFileUrl("send_ignoreData.qml"));
- QObject *object = component.beginCreate(engine.rootContext());
- QVERIFY(object != 0);
+ QScopedPointer<QObject> object(component.beginCreate(engine.rootContext()));
+ QVERIFY(!object.isNull());
object->setProperty("reqType", "GET");
object->setProperty("url", "http://127.0.0.1:14445/testdocument.html");
component.completeCreate();
QTRY_VERIFY(object->property("dataOK").toBool() == true);
-
- delete object;
}
{
@@ -539,15 +499,13 @@ void tst_qqmlxmlhttprequest::send_ignoreData()
QUrl()));
QQmlComponent component(&engine, testFileUrl("send_ignoreData.qml"));
- QObject *object = component.beginCreate(engine.rootContext());
- QVERIFY(object != 0);
+ QScopedPointer<QObject> object(component.beginCreate(engine.rootContext()));
+ QVERIFY(!object.isNull());
object->setProperty("reqType", "HEAD");
object->setProperty("url", "http://127.0.0.1:14445/testdocument.html");
component.completeCreate();
QTRY_VERIFY(object->property("dataOK").toBool() == true);
-
- delete object;
}
{
@@ -558,15 +516,13 @@ void tst_qqmlxmlhttprequest::send_ignoreData()
QUrl()));
QQmlComponent component(&engine, testFileUrl("send_ignoreData.qml"));
- QObject *object = component.beginCreate(engine.rootContext());
- QVERIFY(object != 0);
+ QScopedPointer<QObject> object(component.beginCreate(engine.rootContext()));
+ QVERIFY(!object.isNull());
object->setProperty("reqType", "DELETE");
object->setProperty("url", "http://127.0.0.1:14445/testdocument.html");
component.completeCreate();
QTRY_VERIFY(object->property("dataOK").toBool() == true);
-
- delete object;
}
}
@@ -583,14 +539,12 @@ void tst_qqmlxmlhttprequest::send_withdata()
testFileUrl("testdocument.html")));
QQmlComponent component(&engine, testFileUrl(file_qml));
- QObject *object = component.beginCreate(engine.rootContext());
- QVERIFY(object != 0);
+ QScopedPointer<QObject> object(component.beginCreate(engine.rootContext()));
+ QVERIFY(!object.isNull());
object->setProperty("url", "http://127.0.0.1:14445/testdocument.html");
component.completeCreate();
QTRY_VERIFY(object->property("dataOK").toBool() == true);
-
- delete object;
}
void tst_qqmlxmlhttprequest::send_withdata_data()
@@ -611,8 +565,8 @@ void tst_qqmlxmlhttprequest::send_withdata_data()
void tst_qqmlxmlhttprequest::abort_unsent()
{
QQmlComponent component(&engine, testFileUrl("abort_unsent.qml"));
- QObject *object = component.beginCreate(engine.rootContext());
- QVERIFY(object != 0);
+ QScopedPointer<QObject> object(component.beginCreate(engine.rootContext()));
+ QVERIFY(!object.isNull());
object->setProperty("url", "testdocument.html");
component.completeCreate();
@@ -624,16 +578,14 @@ void tst_qqmlxmlhttprequest::abort_unsent()
QCOMPARE(object->property("responseXML").toBool(), true);
QTRY_VERIFY(object->property("dataOK").toBool() == true);
-
- delete object;
}
// Test abort() cancels an open (but unsent) request
void tst_qqmlxmlhttprequest::abort_opened()
{
QQmlComponent component(&engine, testFileUrl("abort_opened.qml"));
- QObject *object = component.beginCreate(engine.rootContext());
- QVERIFY(object != 0);
+ QScopedPointer<QObject> object(component.beginCreate(engine.rootContext()));
+ QVERIFY(!object.isNull());
object->setProperty("url", "testdocument.html");
component.completeCreate();
@@ -645,8 +597,6 @@ void tst_qqmlxmlhttprequest::abort_opened()
QCOMPARE(object->property("responseXML").toBool(), true);
QTRY_VERIFY(object->property("dataOK").toBool() == true);
-
- delete object;
}
// Test abort() aborts in progress send
@@ -659,8 +609,8 @@ void tst_qqmlxmlhttprequest::abort()
testFileUrl("testdocument.html")));
QQmlComponent component(&engine, testFileUrl("abort.qml"));
- QObject *object = component.beginCreate(engine.rootContext());
- QVERIFY(object != 0);
+ QScopedPointer<QObject> object(component.beginCreate(engine.rootContext()));
+ QVERIFY(!object.isNull());
object->setProperty("urlDummy", "http://127.0.0.1:14449/testdocument.html");
object->setProperty("url", "http://127.0.0.1:14445/testdocument.html");
component.completeCreate();
@@ -670,8 +620,6 @@ void tst_qqmlxmlhttprequest::abort()
QCOMPARE(object->property("endStateUnsent").toBool(), true);
QTRY_VERIFY(object->property("dataOK").toBool() == true);
-
- delete object;
}
void tst_qqmlxmlhttprequest::getResponseHeader()
@@ -686,8 +634,8 @@ void tst_qqmlxmlhttprequest::getResponseHeader()
QQmlComponent component(&engine, testFileUrl("getResponseHeader.qml"));
- QObject *object = component.beginCreate(engine.rootContext());
- QVERIFY(object != 0);
+ QScopedPointer<QObject> object(component.beginCreate(engine.rootContext()));
+ QVERIFY(!object.isNull());
object->setProperty("url", "http://127.0.0.1:14445/testdocument.html");
component.completeCreate();
@@ -709,44 +657,36 @@ void tst_qqmlxmlhttprequest::getResponseHeader()
QCOMPARE(object->property("doneValidHeader").toBool(), true);
QCOMPARE(object->property("doneMultiValidHeader").toBool(), true);
QCOMPARE(object->property("doneCookieHeader").toBool(), true);
-
- delete object;
}
// Test getResponseHeader throws an exception in an invalid state
void tst_qqmlxmlhttprequest::getResponseHeader_unsent()
{
QQmlComponent component(&engine, testFileUrl("getResponseHeader_unsent.qml"));
- QObject *object = component.create();
- QVERIFY(object != 0);
+ QScopedPointer<QObject> object(component.create());
+ QVERIFY(!object.isNull());
QCOMPARE(object->property("test").toBool(), true);
-
- delete object;
}
// Test getResponseHeader throws an exception in an invalid state
void tst_qqmlxmlhttprequest::getResponseHeader_sent()
{
QQmlComponent component(&engine, testFileUrl("getResponseHeader_sent.qml"));
- QObject *object = component.create();
- QVERIFY(object != 0);
+ QScopedPointer<QObject> object(component.create());
+ QVERIFY(!object.isNull());
QCOMPARE(object->property("test").toBool(), true);
-
- delete object;
}
// Invalid arg count throws exception
void tst_qqmlxmlhttprequest::getResponseHeader_args()
{
QQmlComponent component(&engine, testFileUrl("getResponseHeader_args.qml"));
- QObject *object = component.create();
- QVERIFY(object != 0);
+ QScopedPointer<QObject> object(component.create());
+ QVERIFY(!object.isNull());
QTRY_VERIFY(object->property("exceptionThrown").toBool() == true);
-
- delete object;
}
void tst_qqmlxmlhttprequest::getAllResponseHeaders()
@@ -760,8 +700,8 @@ void tst_qqmlxmlhttprequest::getAllResponseHeaders()
testFileUrl("testdocument.html")));
QQmlComponent component(&engine, testFileUrl("getAllResponseHeaders.qml"));
- QObject *object = component.beginCreate(engine.rootContext());
- QVERIFY(object != 0);
+ QScopedPointer<QObject> object(component.beginCreate(engine.rootContext()));
+ QVERIFY(!object.isNull());
object->setProperty("url", "http://127.0.0.1:14445/testdocument.html");
component.completeCreate();
@@ -777,44 +717,36 @@ void tst_qqmlxmlhttprequest::getAllResponseHeaders()
QCOMPARE(object->property("doneState").toBool(), true);
QCOMPARE(object->property("doneHeader").toBool(), true);
-
- delete object;
}
// Test getAllResponseHeaders throws an exception in an invalid state
void tst_qqmlxmlhttprequest::getAllResponseHeaders_unsent()
{
QQmlComponent component(&engine, testFileUrl("getAllResponseHeaders_unsent.qml"));
- QObject *object = component.create();
- QVERIFY(object != 0);
+ QScopedPointer<QObject> object(component.create());
+ QVERIFY(!object.isNull());
QCOMPARE(object->property("test").toBool(), true);
-
- delete object;
}
// Test getAllResponseHeaders throws an exception in an invalid state
void tst_qqmlxmlhttprequest::getAllResponseHeaders_sent()
{
QQmlComponent component(&engine, testFileUrl("getAllResponseHeaders_sent.qml"));
- QObject *object = component.create();
- QVERIFY(object != 0);
+ QScopedPointer<QObject> object(component.create());
+ QVERIFY(!object.isNull());
QCOMPARE(object->property("test").toBool(), true);
-
- delete object;
}
// Invalid arg count throws exception
void tst_qqmlxmlhttprequest::getAllResponseHeaders_args()
{
QQmlComponent component(&engine, testFileUrl("getAllResponseHeaders_args.qml"));
- QObject *object = component.create();
- QVERIFY(object != 0);
+ QScopedPointer<QObject> object(component.create());
+ QVERIFY(!object.isNull());
QTRY_VERIFY(object->property("exceptionThrown").toBool() == true);
-
- delete object;
}
void tst_qqmlxmlhttprequest::status()
@@ -829,8 +761,8 @@ void tst_qqmlxmlhttprequest::status()
testFileUrl("testdocument.html")));
QQmlComponent component(&engine, testFileUrl("status.qml"));
- QObject *object = component.beginCreate(engine.rootContext());
- QVERIFY(object != 0);
+ QScopedPointer<QObject> object(component.beginCreate(engine.rootContext()));
+ QVERIFY(!object.isNull());
object->setProperty("url", "http://127.0.0.1:14445/testdocument.html");
object->setProperty("expectedStatus", status);
component.completeCreate();
@@ -844,8 +776,6 @@ void tst_qqmlxmlhttprequest::status()
QCOMPARE(object->property("loading").toBool(), true);
QCOMPARE(object->property("done").toBool(), true);
QCOMPARE(object->property("resetException").toBool(), true);
-
- delete object;
}
void tst_qqmlxmlhttprequest::status_data()
@@ -870,8 +800,8 @@ void tst_qqmlxmlhttprequest::statusText()
testFileUrl("testdocument.html")));
QQmlComponent component(&engine, testFileUrl("statusText.qml"));
- QObject *object = component.beginCreate(engine.rootContext());
- QVERIFY(object != 0);
+ QScopedPointer<QObject> object(component.beginCreate(engine.rootContext()));
+ QVERIFY(!object.isNull());
object->setProperty("url", "http://127.0.0.1:14445/testdocument.html");
object->setProperty("expectedStatus", statusText);
component.completeCreate();
@@ -885,8 +815,6 @@ void tst_qqmlxmlhttprequest::statusText()
QCOMPARE(object->property("loading").toBool(), true);
QCOMPARE(object->property("done").toBool(), true);
QCOMPARE(object->property("resetException").toBool(), true);
-
- delete object;
}
void tst_qqmlxmlhttprequest::statusText_data()
@@ -912,8 +840,8 @@ void tst_qqmlxmlhttprequest::responseText()
bodyUrl));
QQmlComponent component(&engine, testFileUrl("responseText.qml"));
- QObject *object = component.beginCreate(engine.rootContext());
- QVERIFY(object != 0);
+ QScopedPointer<QObject> object(component.beginCreate(engine.rootContext()));
+ QVERIFY(!object.isNull());
object->setProperty("url", "http://127.0.0.1:14445/testdocument.html");
object->setProperty("expectedText", responseText);
component.completeCreate();
@@ -927,8 +855,6 @@ void tst_qqmlxmlhttprequest::responseText()
QCOMPARE(object->property("loading").toBool(), true);
QCOMPARE(object->property("done").toBool(), true);
QCOMPARE(object->property("reset").toBool(), true);
-
- delete object;
}
void tst_qqmlxmlhttprequest::responseText_data()
@@ -950,11 +876,11 @@ void tst_qqmlxmlhttprequest::nonUtf8()
QFETCH(QString, xmlRootNodeValue);
QQmlComponent component(&engine, testFileUrl("utf16.qml"));
- QObject *object = component.create();
- QVERIFY(object != 0);
+ QScopedPointer<QObject> object(component.create());
+ QVERIFY(!object.isNull());
object->setProperty("fileName", fileName);
- QMetaObject::invokeMethod(object, "startRequest");
+ QMetaObject::invokeMethod(object.data(), "startRequest");
QTRY_VERIFY(object->property("dataOK").toBool() == true);
@@ -964,8 +890,6 @@ void tst_qqmlxmlhttprequest::nonUtf8()
QString rootNodeValue = object->property("responseXmlRootNodeValue").toString();
QCOMPARE(rootNodeValue, xmlRootNodeValue);
}
-
- delete object;
}
void tst_qqmlxmlhttprequest::nonUtf8_data()
@@ -989,8 +913,8 @@ void tst_qqmlxmlhttprequest::nonUtf8_data()
void tst_qqmlxmlhttprequest::invalidMethodUsage()
{
QQmlComponent component(&engine, testFileUrl("invalidMethodUsage.qml"));
- QObject *object = component.create();
- QVERIFY(object != 0);
+ QScopedPointer<QObject> object(component.create());
+ QVERIFY(!object.isNull());
QCOMPARE(object->property("readyState").toBool(), true);
QCOMPARE(object->property("status").toBool(), true);
@@ -1004,8 +928,6 @@ void tst_qqmlxmlhttprequest::invalidMethodUsage()
QCOMPARE(object->property("abort").toBool(), true);
QCOMPARE(object->property("getResponseHeader").toBool(), true);
QCOMPARE(object->property("getAllResponseHeaders").toBool(), true);
-
- delete object;
}
// Test that XMLHttpRequest transparently redirects
@@ -1018,16 +940,14 @@ void tst_qqmlxmlhttprequest::redirects()
server.serveDirectory(dataDirectory());
QQmlComponent component(&engine, testFileUrl("redirects.qml"));
- QObject *object = component.beginCreate(engine.rootContext());
- QVERIFY(object != 0);
+ QScopedPointer<QObject> object(component.beginCreate(engine.rootContext()));
+ QVERIFY(!object.isNull());
object->setProperty("url", "http://127.0.0.1:14445/redirect.html");
object->setProperty("expectedText", "");
component.completeCreate();
QTRY_VERIFY(object->property("done").toBool() == true);
QCOMPARE(object->property("dataOK").toBool(), true);
-
- delete object;
}
{
@@ -1037,16 +957,14 @@ void tst_qqmlxmlhttprequest::redirects()
server.serveDirectory(dataDirectory());
QQmlComponent component(&engine, testFileUrl("redirectError.qml"));
- QObject *object = component.beginCreate(engine.rootContext());
- QVERIFY(object != 0);
+ QScopedPointer<QObject> object(component.beginCreate(engine.rootContext()));
+ QVERIFY(!object.isNull());
object->setProperty("url", "http://127.0.0.1:14445/redirect.html");
object->setProperty("expectedText", "");
component.completeCreate();
QTRY_VERIFY(object->property("done").toBool() == true);
QCOMPARE(object->property("dataOK").toBool(), true);
-
- delete object;
}
{
@@ -1056,8 +974,8 @@ void tst_qqmlxmlhttprequest::redirects()
server.serveDirectory(dataDirectory());
QQmlComponent component(&engine, testFileUrl("redirectRecur.qml"));
- QObject *object = component.beginCreate(engine.rootContext());
- QVERIFY(object != 0);
+ QScopedPointer<QObject> object(component.beginCreate(engine.rootContext()));
+ QVERIFY(!object.isNull());
object->setProperty("url", "http://127.0.0.1:14445/redirect.html");
object->setProperty("expectedText", "");
component.completeCreate();
@@ -1069,92 +987,78 @@ void tst_qqmlxmlhttprequest::redirects()
QVERIFY(object->property("done").toBool() == true);
QCOMPARE(object->property("dataOK").toBool(), true);
-
- delete object;
}
}
void tst_qqmlxmlhttprequest::responseXML_invalid()
{
QQmlComponent component(&engine, testFileUrl("responseXML_invalid.qml"));
- QObject *object = component.create();
- QVERIFY(object != 0);
+ QScopedPointer<QObject> object(component.create());
+ QVERIFY(!object.isNull());
QTRY_VERIFY(object->property("dataOK").toBool() == true);
QCOMPARE(object->property("xmlNull").toBool(), true);
-
- delete object;
}
// Test the Document DOM element
void tst_qqmlxmlhttprequest::document()
{
QQmlComponent component(&engine, testFileUrl("document.qml"));
- QObject *object = component.create();
- QVERIFY(object != 0);
+ QScopedPointer<QObject> object(component.create());
+ QVERIFY(!object.isNull());
QTRY_VERIFY(object->property("dataOK").toBool() == true);
QCOMPARE(object->property("xmlTest").toBool(), true);
-
- delete object;
}
// Test the Element DOM element
void tst_qqmlxmlhttprequest::element()
{
QQmlComponent component(&engine, testFileUrl("element.qml"));
- QObject *object = component.create();
- QVERIFY(object != 0);
+ QScopedPointer<QObject> object(component.create());
+ QVERIFY(!object.isNull());
QTRY_VERIFY(object->property("dataOK").toBool() == true);
QCOMPARE(object->property("xmlTest").toBool(), true);
-
- delete object;
}
// Test the Attr DOM element
void tst_qqmlxmlhttprequest::attr()
{
QQmlComponent component(&engine, testFileUrl("attr.qml"));
- QObject *object = component.create();
- QVERIFY(object != 0);
+ QScopedPointer<QObject> object(component.create());
+ QVERIFY(!object.isNull());
QTRY_VERIFY(object->property("dataOK").toBool() == true);
QCOMPARE(object->property("xmlTest").toBool(), true);
-
- delete object;
}
// Test the Text DOM element
void tst_qqmlxmlhttprequest::text()
{
QQmlComponent component(&engine, testFileUrl("text.qml"));
- QObject *object = component.create();
- QVERIFY(object != 0);
+ QScopedPointer<QObject> object(component.create());
+ QVERIFY(!object.isNull());
QTRY_VERIFY(object->property("dataOK").toBool() == true);
QCOMPARE(object->property("xmlTest").toBool(), true);
-
- delete object;
}
// Test the CDataSection DOM element
void tst_qqmlxmlhttprequest::cdata()
{
QQmlComponent component(&engine, testFileUrl("cdata.qml"));
- QObject *object = component.create();
- QVERIFY(object != 0);
+ QScopedPointer<QObject> object(component.create());
+ QVERIFY(!object.isNull());
QTRY_VERIFY(object->property("dataOK").toBool() == true);
QCOMPARE(object->property("xmlTest").toBool(), true);
-
- delete object;
}
void tst_qqmlxmlhttprequest::stateChangeCallingContext()
@@ -1171,11 +1075,10 @@ void tst_qqmlxmlhttprequest::stateChangeCallingContext()
server.serveDirectory(dataDirectory(), TestHTTPServer::Delay);
QQmlComponent component(&engine, testFileUrl("stateChangeCallingContext.qml"));
- QObject *object = component.create();
- QVERIFY(object != 0);
+ QScopedPointer<QObject> object(component.create());
+ QVERIFY(!object.isNull());
server.sendDelayedItem();
QTRY_VERIFY(object->property("success").toBool() == true);
- delete object;
}
QTEST_MAIN(tst_qqmlxmlhttprequest)
diff --git a/tests/auto/quick/qquickitem/tst_qquickitem.cpp b/tests/auto/quick/qquickitem/tst_qquickitem.cpp
index 97e002361b..2c6dcd72ba 100644
--- a/tests/auto/quick/qquickitem/tst_qquickitem.cpp
+++ b/tests/auto/quick/qquickitem/tst_qquickitem.cpp
@@ -44,7 +44,6 @@
#include <QtQuick/qquickitem.h>
#include <QtQuick/qquickwindow.h>
#include <QtQuick/qquickview.h>
-#include <QtWidgets/QGraphicsSceneMouseEvent>
#include "private/qquickfocusscope_p.h"
#include "private/qquickitem_p.h"
#include <qpa/qwindowsysteminterface.h>
@@ -1151,6 +1150,30 @@ void tst_qquickitem::enabledFocus()
QCOMPARE(child2.hasFocus(), false);
QCOMPARE(child2.hasActiveFocus(), false);
QCOMPARE(window.activeFocusItem(), static_cast<QQuickItem *>(&child1));
+
+ child2.setFocus(true);
+ QCOMPARE(root.isEnabled(), true);
+ QCOMPARE(root.hasFocus(), true);
+ QCOMPARE(root.hasActiveFocus(), true);
+ QCOMPARE(child1.isEnabled(), true);
+ QCOMPARE(child1.hasFocus(), false);
+ QCOMPARE(child1.hasActiveFocus(), false);
+ QCOMPARE(child2.isEnabled(), false);
+ QCOMPARE(child2.hasFocus(), true);
+ QCOMPARE(child2.hasActiveFocus(), false);
+ QCOMPARE(window.activeFocusItem(), static_cast<QQuickItem *>(&root));
+
+ root.setEnabled(false);
+ QCOMPARE(root.isEnabled(), false);
+ QCOMPARE(root.hasFocus(), true);
+ QCOMPARE(root.hasActiveFocus(), false);
+ QCOMPARE(child1.isEnabled(), false);
+ QCOMPARE(child1.hasFocus(), false);
+ QCOMPARE(child1.hasActiveFocus(), false);
+ QCOMPARE(child2.isEnabled(), false);
+ QCOMPARE(child2.hasFocus(), true);
+ QCOMPARE(child2.hasActiveFocus(), false);
+ QCOMPARE(window.activeFocusItem(), window.contentItem());
}
static inline QByteArray msgItem(const QQuickItem *item)
diff --git a/tests/auto/quick/qquicklistview/data/headerchangesviewport.qml b/tests/auto/quick/qquicklistview/data/headerchangesviewport.qml
new file mode 100644
index 0000000000..b32f7a1236
--- /dev/null
+++ b/tests/auto/quick/qquicklistview/data/headerchangesviewport.qml
@@ -0,0 +1,19 @@
+import QtQuick 2.0
+
+Rectangle {
+ width: 240
+ height: 320
+ color: "#ffffff"
+ ListView {
+ id: list
+ anchors.fill: parent
+ objectName: "list"
+ delegate: Text {}
+ header: Text {
+ objectName: "header"
+ text: "ninjas"
+ height: headerHeight
+ width: headerWidth
+ }
+ }
+}
diff --git a/tests/auto/quick/qquicklistview/data/typedModel.qml b/tests/auto/quick/qquicklistview/data/typedModel.qml
new file mode 100644
index 0000000000..d2b3f7e42f
--- /dev/null
+++ b/tests/auto/quick/qquicklistview/data/typedModel.qml
@@ -0,0 +1,23 @@
+import QtQuick 2.0
+
+ListView {
+ width: 100
+ height: 100
+
+ delegate: Item {
+ width: 100
+ height: 10
+ }
+ model: listModel
+
+ ListModel {
+ id: listModel
+
+ ListElement { label: "a" }
+ ListElement { label: "b" }
+ ListElement { label: "c" }
+ ListElement { label: "d" }
+ ListElement { label: "e" }
+ ListElement { label: "f" }
+ }
+}
diff --git a/tests/auto/quick/qquicklistview/tst_qquicklistview.cpp b/tests/auto/quick/qquicklistview/tst_qquicklistview.cpp
index f62151c2d8..fb0b1c95ca 100644
--- a/tests/auto/quick/qquicklistview/tst_qquicklistview.cpp
+++ b/tests/auto/quick/qquicklistview/tst_qquicklistview.cpp
@@ -150,6 +150,7 @@ private slots:
void header();
void header_data();
void header_delayItemCreation();
+ void headerChangesViewport();
void footer();
void footer_data();
void extents();
@@ -213,6 +214,8 @@ private slots:
void outsideViewportChangeNotAffectingView();
void testProxyModelChangedAfterMove();
+ void typedModel();
+
private:
template <class T> void items(const QUrl &source);
template <class T> void changed(const QUrl &source);
@@ -3655,6 +3658,35 @@ void tst_QQuickListView::header_delayItemCreation()
delete window;
}
+void tst_QQuickListView::headerChangesViewport()
+{
+ QQuickView *window = getView();
+ window->rootContext()->setContextProperty("headerHeight", 20);
+ window->rootContext()->setContextProperty("headerWidth", 240);
+ window->setSource(testFileUrl("headerchangesviewport.qml"));
+
+ QQuickListView *listview = findItem<QQuickListView>(window->rootObject(), "list");
+ QTRY_VERIFY(listview != 0);
+ QTRY_COMPARE(QQuickItemPrivate::get(listview)->polishScheduled, false);
+
+ QQuickItem *contentItem = listview->contentItem();
+ QTRY_VERIFY(contentItem != 0);
+
+ QQuickText *header = 0;
+ QTRY_VERIFY(header = findItem<QQuickText>(contentItem, "header"));
+ QVERIFY(header == listview->headerItem());
+
+ QCOMPARE(header->height(), 20.);
+ QCOMPARE(listview->contentHeight(), 20.);
+
+ // change height
+ window->rootContext()->setContextProperty("headerHeight", 50);
+
+ // verify that list content height updates also
+ QCOMPARE(header->height(), 50.);
+ QCOMPARE(listview->contentHeight(), 50.);
+}
+
void tst_QQuickListView::footer()
{
QFETCH(QQuickListView::Orientation, orientation);
@@ -6960,6 +6992,24 @@ void tst_QQuickListView::testProxyModelChangedAfterMove()
delete window;
}
+void tst_QQuickListView::typedModel()
+{
+ QQmlEngine engine;
+ QQmlComponent component(&engine, testFileUrl("typedModel.qml"));
+
+ QScopedPointer<QObject> object(component.create());
+
+ QQuickListView *listview = qobject_cast<QQuickListView *>(object.data());
+ QVERIFY(listview);
+
+ QCOMPARE(listview->count(), 6);
+
+ QQmlListModel *listModel = 0;
+
+ listview->setModel(QVariant::fromValue(listModel));
+ QCOMPARE(listview->count(), 0);
+}
+
QTEST_MAIN(tst_QQuickListView)
#include "tst_qquicklistview.moc"
diff --git a/tests/auto/shared/testhttpserver.cpp b/tests/auto/shared/testhttpserver.cpp
index fd681710de..20df0c12f5 100644
--- a/tests/auto/shared/testhttpserver.cpp
+++ b/tests/auto/shared/testhttpserver.cpp
@@ -88,7 +88,7 @@ The following request urls will then result in the appropriate action:
\endtable
*/
TestHTTPServer::TestHTTPServer(quint16 port)
-: m_hasFailed(false)
+: m_state(AwaitingHeader)
{
QObject::connect(&server, SIGNAL(newConnection()), this, SLOT(newConnection()));
@@ -122,7 +122,8 @@ void TestHTTPServer::addRedirect(const QString &filename, const QString &redirec
bool TestHTTPServer::wait(const QUrl &expect, const QUrl &reply, const QUrl &body)
{
- m_hasFailed = false;
+ m_state = AwaitingHeader;
+ m_data.clear();
QFile expectFile(expect.toLocalFile());
if (!expectFile.open(QIODevice::ReadOnly)) return false;
@@ -175,7 +176,7 @@ bool TestHTTPServer::wait(const QUrl &expect, const QUrl &reply, const QUrl &bod
bool TestHTTPServer::hasFailed() const
{
- return m_hasFailed;
+ return m_state == Failed;
}
void TestHTTPServer::newConnection()
@@ -216,33 +217,41 @@ void TestHTTPServer::readyRead()
return;
}
- if (m_hasFailed || (waitData.body.isEmpty() && waitData.headers.count() == 0)) {
+ if (m_state == Failed || (waitData.body.isEmpty() && waitData.headers.count() == 0)) {
qWarning() << "TestHTTPServer: Unexpected data" << socket->readAll();
return;
}
- QByteArray line;
- while (!(line = socket->readLine()).isEmpty()) {
- line.replace('\r', "");
- if (line.at(0) == '\n') {
- QByteArray data = socket->readAll();
- if (waitData.body != data) {
- qWarning() << "TestHTTPServer: Unexpected data" << data << "\nExpected: " << waitData.body;
- m_hasFailed = true;
- socket->disconnectFromHost();
- return;
+ if (m_state == AwaitingHeader) {
+ QByteArray line;
+ while (!(line = socket->readLine()).isEmpty()) {
+ line.replace('\r', "");
+ if (line.at(0) == '\n') {
+ m_state = AwaitingData;
+ m_data += socket->readAll();
+ break;
+ } else {
+ if (!waitData.headers.contains(line)) {
+ qWarning() << "TestHTTPServer: Unexpected header:" << line << "\nExpected headers: " << waitData.headers;
+ m_state = Failed;
+ socket->disconnectFromHost();
+ return;
+ }
}
}
- else if (!waitData.headers.contains(line)) {
- qWarning() << "TestHTTPServer: Unexpected header:" << line << "\nExpected headers: " << waitData.headers;
- m_hasFailed = true;
- socket->disconnectFromHost();
- return;
- }
+ } else {
+ m_data += socket->readAll();
}
- socket->write(replyData);
- socket->disconnectFromHost();
+ if (!m_data.isEmpty() || waitData.body.isEmpty()) {
+ if (waitData.body != m_data) {
+ qWarning() << "TestHTTPServer: Unexpected data" << m_data << "\nExpected: " << waitData.body;
+ m_state = Failed;
+ } else {
+ socket->write(replyData);
+ }
+ socket->disconnectFromHost();
+ }
}
bool TestHTTPServer::reply(QTcpSocket *socket, const QByteArray &fileName)
diff --git a/tests/auto/shared/testhttpserver.h b/tests/auto/shared/testhttpserver.h
index ce0501f170..ae7d137143 100644
--- a/tests/auto/shared/testhttpserver.h
+++ b/tests/auto/shared/testhttpserver.h
@@ -74,6 +74,12 @@ private slots:
void sendOne();
private:
+ enum State {
+ AwaitingHeader,
+ AwaitingData,
+ Failed
+ };
+
void serveGET(QTcpSocket *, const QByteArray &);
bool reply(QTcpSocket *, const QByteArray &);
@@ -87,7 +93,8 @@ private:
} waitData;
QByteArray replyData;
QByteArray bodyData;
- bool m_hasFailed;
+ QByteArray m_data;
+ State m_state;
QHash<QString,QString> aliases;
QHash<QString,QString> redirects;