diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/plugins/qmltooling/qmldbg_profiler/qqmlprofileradapter.cpp | 2 | ||||
-rw-r--r-- | src/plugins/qmltooling/qmldbg_server/qqmldebugserver.cpp | 1 | ||||
-rw-r--r-- | src/qml/compiler/qqmltypecompiler.cpp | 40 | ||||
-rw-r--r-- | src/qml/debugger/qqmlprofiler_p.h | 11 | ||||
-rw-r--r-- | src/qml/jit/qv4isel_masm.cpp | 62 | ||||
-rw-r--r-- | src/qml/jsruntime/qv4persistent.cpp | 63 | ||||
-rw-r--r-- | src/qml/jsruntime/qv4persistent_p.h | 8 | ||||
-rw-r--r-- | src/qml/jsruntime/qv4profiling.cpp | 29 | ||||
-rw-r--r-- | src/qml/jsruntime/qv4profiling_p.h | 1 | ||||
-rw-r--r-- | src/qml/jsruntime/qv4script.cpp | 16 | ||||
-rw-r--r-- | src/qml/jsruntime/qv4script_p.h | 4 | ||||
-rw-r--r-- | src/qml/qml/qqmlcontextwrapper.cpp | 13 | ||||
-rw-r--r-- | src/qml/qml/qqmlobjectcreator.cpp | 23 | ||||
-rw-r--r-- | src/qml/qml/qqmlobjectcreator_p.h | 4 | ||||
-rw-r--r-- | src/qml/qml/qqmltypeloader.cpp | 8 | ||||
-rw-r--r-- | src/qml/qml/qqmlxmlhttprequest.cpp | 6 | ||||
-rw-r--r-- | src/quick/items/qquickitem.cpp | 89 | ||||
-rw-r--r-- | src/quick/items/qquickitem_p.h | 8 | ||||
-rw-r--r-- | src/quick/util/qquickglobal.cpp | 2 |
19 files changed, 280 insertions, 110 deletions
diff --git a/src/plugins/qmltooling/qmldbg_profiler/qqmlprofileradapter.cpp b/src/plugins/qmltooling/qmldbg_profiler/qqmlprofileradapter.cpp index 349c181d13..245900abae 100644 --- a/src/plugins/qmltooling/qmldbg_profiler/qqmlprofileradapter.cpp +++ b/src/plugins/qmltooling/qmldbg_profiler/qqmlprofileradapter.cpp @@ -81,7 +81,7 @@ static void qQmlProfilerDataToByteArrays(const QQmlProfilerData *d, QList<QByteA ds << QQmlProfilerDefinitions::QmlBinding; break; case QQmlProfilerDefinitions::RangeData: - ds << d->detailString; + ds << (d->detailString.isEmpty() ? d->detailUrl.toString() : d->detailString); break; case QQmlProfilerDefinitions::RangeLocation: ds << (d->detailUrl.isEmpty() ? d->detailString : d->detailUrl.toString()) << d->x diff --git a/src/plugins/qmltooling/qmldbg_server/qqmldebugserver.cpp b/src/plugins/qmltooling/qmldbg_server/qqmldebugserver.cpp index 1cfebea03c..93e1d0c030 100644 --- a/src/plugins/qmltooling/qmldbg_server/qqmldebugserver.cpp +++ b/src/plugins/qmltooling/qmldbg_server/qqmldebugserver.cpp @@ -112,7 +112,6 @@ private: QString m_pluginName; int m_portFrom; int m_portTo; - bool m_block; QString m_hostAddress; QString m_fileName; }; diff --git a/src/qml/compiler/qqmltypecompiler.cpp b/src/qml/compiler/qqmltypecompiler.cpp index 80aa617c53..80ffafda72 100644 --- a/src/qml/compiler/qqmltypecompiler.cpp +++ b/src/qml/compiler/qqmltypecompiler.cpp @@ -667,17 +667,14 @@ bool QQmlPropertyCacheCreator::createMetaObject(int objectIndex, const QmlIR::Ob } // First set up notify signals for properties - first normal, then var, then alias - enum { NSS_Normal = 0, NSS_Var = 1, NSS_Alias = 2 }; + enum { NSS_Normal = 0, NSS_Alias = 1 }; for (int ii = NSS_Normal; ii <= NSS_Alias; ++ii) { // 0 == normal, 1 == var, 2 == alias - if (ii == NSS_Var && varPropCount == 0) continue; - else if (ii == NSS_Alias && aliasCount == 0) continue; + if (ii == NSS_Alias && aliasCount == 0) continue; for (const QmlIR::Property *p = obj->firstProperty(); p; p = p->next) { - if ((ii == NSS_Normal && (p->type == QV4::CompiledData::Property::Alias || - p->type == QV4::CompiledData::Property::Var)) || - ((ii == NSS_Var) && (p->type != QV4::CompiledData::Property::Var)) || - ((ii == NSS_Alias) && (p->type != QV4::CompiledData::Property::Alias))) + if ((ii == NSS_Normal && p->type == QV4::CompiledData::Property::Alias) || + (ii == NSS_Alias && p->type != QV4::CompiledData::Property::Alias)) continue; quint32 flags = QQmlPropertyData::IsSignal | QQmlPropertyData::IsFunction | @@ -1046,16 +1043,29 @@ bool SignalHandlerConverter::convertSignalHandlerExpressionsToFunctionDeclaratio paramList = paramList->finish(); QmlIR::CompiledFunctionOrExpression *foe = obj->functionsAndExpressions->slowAt(binding->value.compiledScriptIndex); - QQmlJS::AST::Statement *statement = static_cast<QQmlJS::AST::Statement*>(foe->node); - QQmlJS::AST::SourceElement *sourceElement = new (pool) QQmlJS::AST::StatementSourceElement(statement); - QQmlJS::AST::SourceElements *elements = new (pool) QQmlJS::AST::SourceElements(sourceElement); - elements = elements->finish(); - - QQmlJS::AST::FunctionBody *body = new (pool) QQmlJS::AST::FunctionBody(elements); + QQmlJS::AST::FunctionDeclaration *functionDeclaration = 0; + if (QQmlJS::AST::ExpressionStatement *es = QQmlJS::AST::cast<QQmlJS::AST::ExpressionStatement*>(foe->node)) { + if (QQmlJS::AST::FunctionExpression *fe = QQmlJS::AST::cast<QQmlJS::AST::FunctionExpression*>(es->expression)) { + functionDeclaration = new (pool) QQmlJS::AST::FunctionDeclaration(fe->name, fe->formals, fe->body); + functionDeclaration->functionToken = fe->functionToken; + functionDeclaration->identifierToken = fe->identifierToken; + functionDeclaration->lparenToken = fe->lparenToken; + functionDeclaration->rparenToken = fe->rparenToken; + functionDeclaration->lbraceToken = fe->lbraceToken; + functionDeclaration->rbraceToken = fe->rbraceToken; + } + } + if (!functionDeclaration) { + QQmlJS::AST::Statement *statement = static_cast<QQmlJS::AST::Statement*>(foe->node); + QQmlJS::AST::SourceElement *sourceElement = new (pool) QQmlJS::AST::StatementSourceElement(statement); + QQmlJS::AST::SourceElements *elements = new (pool) QQmlJS::AST::SourceElements(sourceElement); + elements = elements->finish(); - QQmlJS::AST::FunctionDeclaration *functionDeclaration = new (pool) QQmlJS::AST::FunctionDeclaration(compiler->newStringRef(stringAt(binding->propertyNameIndex)), paramList, body); - functionDeclaration->functionToken = foe->node->firstSourceLocation(); + QQmlJS::AST::FunctionBody *body = new (pool) QQmlJS::AST::FunctionBody(elements); + functionDeclaration = new (pool) QQmlJS::AST::FunctionDeclaration(compiler->newStringRef(stringAt(binding->propertyNameIndex)), paramList, body); + functionDeclaration->functionToken = foe->node->firstSourceLocation(); + } foe->node = functionDeclaration; binding->propertyNameIndex = compiler->registerString(propertyName); binding->flags |= QV4::CompiledData::Binding::IsSignalHandlerExpression; diff --git a/src/qml/debugger/qqmlprofiler_p.h b/src/qml/debugger/qqmlprofiler_p.h index 3c8337c969..7e29c3ede6 100644 --- a/src/qml/debugger/qqmlprofiler_p.h +++ b/src/qml/debugger/qqmlprofiler_p.h @@ -99,8 +99,9 @@ struct Q_AUTOTEST_EXPORT QQmlProfilerData int messageType; //bit field of QQmlProfilerService::Message int detailType; + // RangeData prefers detailString; RangeLocation prefers detailUrl. QString detailString; //used by RangeData and possibly by RangeLocation - QUrl detailUrl; //used by RangeLocation, overrides detailString + QUrl detailUrl; //used by RangeLocation and possibly by RangeData int x; //used by RangeLocation int y; //used by RangeLocation @@ -120,11 +121,11 @@ public: // Have toByteArrays() construct another RangeData event from the same QString later. // This is somewhat pointless but important for backwards compatibility. - void startCompiling(const QString &name) + void startCompiling(const QUrl &url) { m_data.append(QQmlProfilerData(m_timer.nsecsElapsed(), (1 << RangeStart | 1 << RangeLocation | 1 << RangeData), - 1 << Compiling, name, 1, 1)); + 1 << Compiling, url, 1, 1)); } void startHandlingSignal(const QQmlSourceLocation &location) @@ -217,10 +218,10 @@ struct QQmlHandlingSignalProfiler : public QQmlProfilerHelper { }; struct QQmlCompilingProfiler : public QQmlProfilerHelper { - QQmlCompilingProfiler(QQmlProfiler *profiler, const QString &name) : + QQmlCompilingProfiler(QQmlProfiler *profiler, const QUrl &url) : QQmlProfilerHelper(profiler) { - Q_QML_PROFILE(QQmlProfilerDefinitions::ProfileCompiling, profiler, startCompiling(name)); + Q_QML_PROFILE(QQmlProfilerDefinitions::ProfileCompiling, profiler, startCompiling(url)); } ~QQmlCompilingProfiler() diff --git a/src/qml/jit/qv4isel_masm.cpp b/src/qml/jit/qv4isel_masm.cpp index acead2088b..5dfd891b80 100644 --- a/src/qml/jit/qv4isel_masm.cpp +++ b/src/qml/jit/qv4isel_masm.cpp @@ -45,6 +45,7 @@ #include "qv4binop_p.h" #include <QtCore/QBuffer> +#include <QtCore/QCoreApplication> #include <assembler/LinkBuffer.h> #include <WTFStubs.h> @@ -120,6 +121,19 @@ static void printDisassembledOutputWithCalls(QByteArray processedOutput, const Q qDebug("%s", processedOutput.constData()); } +#if defined(Q_OS_LINUX) +static FILE *pmap; + +static void qt_closePmap() +{ + if (pmap) { + fclose(pmap); + pmap = 0; + } +} + +#endif + JSC::MacroAssemblerCodeRef Assembler::link(int *codeSize) { Label endOfCode = label(); @@ -167,6 +181,8 @@ JSC::MacroAssemblerCodeRef Assembler::link(int *codeSize) *codeSize = linkBuffer.offsetOf(endOfCode); + QByteArray name; + JSC::MacroAssemblerCodeRef codeRef; static bool showCode = !qgetenv("QV4_SHOW_ASM").isNull(); @@ -175,7 +191,7 @@ JSC::MacroAssemblerCodeRef Assembler::link(int *codeSize) buf.open(QIODevice::WriteOnly); WTF::setDataFile(new QIODevicePrintStream(&buf)); - QByteArray name = _function->name->toUtf8(); + name = _function->name->toUtf8(); if (name.isEmpty()) { name = QByteArray::number(quintptr(_function), 16); name.prepend("IR::Function(0x"); @@ -189,6 +205,50 @@ JSC::MacroAssemblerCodeRef Assembler::link(int *codeSize) codeRef = linkBuffer.finalizeCodeWithoutDisassembly(); } +#if defined(Q_OS_LINUX) + // This implements writing of JIT'd addresses so that perf can find the + // symbol names. + // + // Perf expects the mapping to be in a certain place and have certain + // content, for more information, see: + // https://github.com/torvalds/linux/blob/master/tools/perf/Documentation/jit-interface.txt + static bool doProfile = !qEnvironmentVariableIsEmpty("QV4_PROFILE_WRITE_PERF_MAP"); + static bool profileInitialized = false; + if (doProfile && !profileInitialized) { + profileInitialized = true; + + char pname[PATH_MAX]; + snprintf(pname, PATH_MAX - 1, "/tmp/perf-%lu.map", + (unsigned long)QCoreApplication::applicationPid()); + + pmap = fopen(pname, "w"); + if (!pmap) + qWarning("QV4: Can't write %s, call stacks will not contain JavaScript function names", pname); + + // make sure we clean up nicely + std::atexit(qt_closePmap); + } + + if (pmap) { + // this may have been pre-populated, if QV4_SHOW_ASM was on + if (name.isEmpty()) { + name = _function->name->toUtf8(); + if (name.isEmpty()) { + name = QByteArray::number(quintptr(_function), 16); + name.prepend("IR::Function(0x"); + name.append(")"); + } + } + + fprintf(pmap, "%llx %x %.*s\n", + (long long unsigned int)codeRef.code().executableAddress(), + *codeSize, + name.length(), + name.constData()); + fflush(pmap); + } +#endif + return codeRef; } diff --git a/src/qml/jsruntime/qv4persistent.cpp b/src/qml/jsruntime/qv4persistent.cpp index 4ec7103644..4a0f84b685 100644 --- a/src/qml/jsruntime/qv4persistent.cpp +++ b/src/qml/jsruntime/qv4persistent.cpp @@ -93,6 +93,43 @@ Page *allocatePage(PersistentValueStorage *storage) } +PersistentValueStorage::Iterator::Iterator(void *p, int idx) + : p(p), index(idx) +{ + Page *page = static_cast<Page *>(p); + if (page) + ++page->header.refCount; +} + +PersistentValueStorage::Iterator::Iterator(const PersistentValueStorage::Iterator &o) + : p(o.p), index(o.index) +{ + Page *page = static_cast<Page *>(p); + if (page) + ++page->header.refCount; +} + +PersistentValueStorage::Iterator &PersistentValueStorage::Iterator::operator=(const PersistentValueStorage::Iterator &o) +{ + Page *page = static_cast<Page *>(p); + if (page && !--page->header.refCount) + freePage(p); + p = o.p; + index = o.index; + page = static_cast<Page *>(p); + if (page) + ++page->header.refCount; + + return *this; +} + +PersistentValueStorage::Iterator::~Iterator() +{ + Page *page = static_cast<Page *>(p); + if (page && !--page->header.refCount) + freePage(page); +} + PersistentValueStorage::Iterator &PersistentValueStorage::Iterator::operator++() { while (p) { while (index < kEntriesPerPage - 1) { @@ -101,7 +138,12 @@ PersistentValueStorage::Iterator &PersistentValueStorage::Iterator::operator++() return *this; } index = -1; - p = static_cast<Page *>(p)->header.next; + Page *next = static_cast<Page *>(p)->header.next; + if (!--static_cast<Page *>(p)->header.refCount) + freePage(p); + p = next; + if (next) + ++next->header.refCount; } index = 0; return *this; @@ -165,13 +207,8 @@ void PersistentValueStorage::free(Value *v) v->setTag(QV4::Value::Empty_Type); v->setInt_32(p->header.freeList); p->header.freeList = v - p->values; - if (!--p->header.refCount) { - if (p->header.prev) - *p->header.prev = p->header.next; - if (p->header.next) - p->header.next->header.prev = p->header.prev; - p->header.alloc.deallocate(); - } + if (!--p->header.refCount) + freePage(p); } static void drainMarkStack(QV4::ExecutionEngine *engine, Value *markBase) @@ -204,6 +241,16 @@ ExecutionEngine *PersistentValueStorage::getEngine(Value *v) return getPage(v)->header.engine; } +void PersistentValueStorage::freePage(void *page) +{ + Page *p = static_cast<Page *>(page); + if (p->header.prev) + *p->header.prev = p->header.next; + if (p->header.next) + p->header.next->header.prev = p->header.prev; + p->header.alloc.deallocate(); +} + PersistentValue::PersistentValue(const PersistentValue &other) : val(0) diff --git a/src/qml/jsruntime/qv4persistent_p.h b/src/qml/jsruntime/qv4persistent_p.h index 858734e9ed..67a76742d1 100644 --- a/src/qml/jsruntime/qv4persistent_p.h +++ b/src/qml/jsruntime/qv4persistent_p.h @@ -51,8 +51,10 @@ struct Q_QML_EXPORT PersistentValueStorage void mark(ExecutionEngine *e); struct Iterator { - Q_DECL_CONSTEXPR Iterator(void *p, int idx) - : p(p), index(idx) {} + Iterator(void *p, int idx); + Iterator(const Iterator &o); + Iterator & operator=(const Iterator &o); + ~Iterator(); void *p; int index; Iterator &operator++(); @@ -68,6 +70,8 @@ struct Q_QML_EXPORT PersistentValueStorage ExecutionEngine *engine; void *firstPage; +private: + static void freePage(void *page); }; class Q_QML_EXPORT PersistentValue diff --git a/src/qml/jsruntime/qv4profiling.cpp b/src/qml/jsruntime/qv4profiling.cpp index 9b77599904..b62f367601 100644 --- a/src/qml/jsruntime/qv4profiling.cpp +++ b/src/qml/jsruntime/qv4profiling.cpp @@ -37,8 +37,8 @@ QT_BEGIN_NAMESPACE -using namespace QV4; -using namespace QV4::Profiling; +namespace QV4 { +namespace Profiling { FunctionCallProperties FunctionCall::resolve() const { @@ -63,26 +63,28 @@ Profiler::Profiler(QV4::ExecutionEngine *engine) : featuresEnabled(0), m_engine( m_timer.start(); } -struct FunctionCallComparator { - bool operator()(const FunctionCallProperties &p1, const FunctionCallProperties &p2) - { return p1.start < p2.start; } -}; - void Profiler::stopProfiling() { featuresEnabled = 0; reportData(); } +bool operator<(const FunctionCall &call1, const FunctionCall &call2) +{ + return call1.m_start < call2.m_start || + (call1.m_start == call2.m_start && (call1.m_end < call2.m_end || + (call1.m_end == call2.m_end && call1.m_function < call2.m_function))); +} + void Profiler::reportData() { + std::sort(m_data.begin(), m_data.end()); QVector<FunctionCallProperties> resolved; resolved.reserve(m_data.size()); - FunctionCallComparator comp; - foreach (const FunctionCall &call, m_data) { - FunctionCallProperties props = call.resolve(); - resolved.insert(std::upper_bound(resolved.begin(), resolved.end(), props, comp), props); - } + + foreach (const FunctionCall &call, m_data) + resolved.append(call.resolve()); + emit dataReady(resolved, m_memory_data); m_data.clear(); m_memory_data.clear(); @@ -111,4 +113,7 @@ void Profiler::startProfiling(quint64 features) } } +} // namespace Profiling +} // namespace QV4 + QT_END_NAMESPACE diff --git a/src/qml/jsruntime/qv4profiling_p.h b/src/qml/jsruntime/qv4profiling_p.h index cc00af0193..505d393a3d 100644 --- a/src/qml/jsruntime/qv4profiling_p.h +++ b/src/qml/jsruntime/qv4profiling_p.h @@ -104,6 +104,7 @@ public: FunctionCallProperties resolve() const; private: + friend bool operator<(const FunctionCall &call1, const FunctionCall &call2); Function *m_function; qint64 m_start; diff --git a/src/qml/jsruntime/qv4script.cpp b/src/qml/jsruntime/qv4script.cpp index 14b8b878bd..7067d10e22 100644 --- a/src/qml/jsruntime/qv4script.cpp +++ b/src/qml/jsruntime/qv4script.cpp @@ -104,18 +104,6 @@ Heap::QmlBindingWrapper::QmlBindingWrapper(QV4::ExecutionContext *scope, Functio internalClass->engine->popContext(); } -Heap::QmlBindingWrapper::QmlBindingWrapper(QV4::ExecutionContext *scope, QV4::QmlContextWrapper *qml) - : Heap::FunctionObject(scope, scope->d()->engine->id_eval(), /*createProto = */ false) -{ - Q_ASSERT(scope->inUse()); - - Scope s(scope); - Scoped<QV4::QmlBindingWrapper> protectThis(s, this); - - this->scope = scope->newQmlContext(qml); - internalClass->engine->popContext(); -} - ReturnedValue QmlBindingWrapper::call(const Managed *that, CallData *callData) { const QmlBindingWrapper *This = static_cast<const QmlBindingWrapper *>(that); @@ -152,8 +140,8 @@ Heap::FunctionObject *QmlBindingWrapper::createQmlCallableForFunction(QQmlContex QV4::Scope valueScope(engine); QV4::Scoped<QmlContextWrapper> qmlScopeObject(valueScope, QV4::QmlContextWrapper::qmlScope(engine, qmlContext, scopeObject)); ScopedContext global(valueScope, valueScope.engine->rootContext()); - QV4::Scoped<QV4::QmlBindingWrapper> wrapper(valueScope, engine->memoryManager->alloc<QV4::QmlBindingWrapper>(global, qmlScopeObject)); - QV4::Scoped<QmlContext> wrapperContext(valueScope, wrapper->context()); + QV4::Scoped<QmlContext> wrapperContext(valueScope, global->newQmlContext(qmlScopeObject)); + engine->popContext(); if (!signalParameters.isEmpty()) { if (error) diff --git a/src/qml/jsruntime/qv4script_p.h b/src/qml/jsruntime/qv4script_p.h index 22714496f8..fad011f88a 100644 --- a/src/qml/jsruntime/qv4script_p.h +++ b/src/qml/jsruntime/qv4script_p.h @@ -88,8 +88,6 @@ struct ContextStateSaver { namespace Heap { struct QmlBindingWrapper : Heap::FunctionObject { QmlBindingWrapper(QV4::ExecutionContext *scope, Function *f, QV4::QmlContextWrapper *qml); - // Constructor for QML functions and signal handlers, resulting binding wrapper is not callable! - QmlBindingWrapper(QV4::ExecutionContext *scope, QV4::QmlContextWrapper *qml); }; } @@ -99,8 +97,6 @@ struct Q_QML_EXPORT QmlBindingWrapper : FunctionObject { static ReturnedValue call(const Managed *that, CallData *callData); - Heap::QmlContext *context() const { return static_cast<Heap::QmlContext *>(d()->scope.ptr); } - static Heap::FunctionObject *createQmlCallableForFunction(QQmlContextData *qmlContext, QObject *scopeObject, QV4::Function *runtimeFunction, const QList<QByteArray> &signalParameters = QList<QByteArray>(), QString *error = 0); }; diff --git a/src/qml/qml/qqmlcontextwrapper.cpp b/src/qml/qml/qqmlcontextwrapper.cpp index 1007029416..99a5fe56ce 100644 --- a/src/qml/qml/qqmlcontextwrapper.cpp +++ b/src/qml/qml/qqmlcontextwrapper.cpp @@ -100,23 +100,14 @@ ReturnedValue QmlContextWrapper::get(const Managed *m, String *name, bool *hasPr QV4::ExecutionEngine *v4 = resource->engine(); QV4::Scope scope(v4); - // In V8 the JS global object would come _before_ the QML global object, - // so simulate that here. - bool hasProp; - QV4::ScopedValue result(scope, v4->globalObject->get(name, &hasProp)); - if (hasProp) { - if (hasProperty) - *hasProperty = hasProp; - return result->asReturnedValue(); - } - if (resource->d()->isNullWrapper) return Object::get(m, name, hasProperty); if (v4->callingQmlContext() != resource->d()->context) return Object::get(m, name, hasProperty); - result = Object::get(m, name, &hasProp); + bool hasProp; + QV4::ScopedValue result(scope, Object::get(m, name, &hasProp)); if (hasProp) { if (hasProperty) *hasProperty = hasProp; diff --git a/src/qml/qml/qqmlobjectcreator.cpp b/src/qml/qml/qqmlobjectcreator.cpp index 0b977f2551..b55973cdc8 100644 --- a/src/qml/qml/qqmlobjectcreator.cpp +++ b/src/qml/qml/qqmlobjectcreator.cpp @@ -120,7 +120,7 @@ void QQmlObjectCreator::init(QQmlContextData *providedParentContext) _ddata = 0; _propertyCache = 0; _vmeMetaObject = 0; - _qmlBindingWrapper = 0; + _qmlContext = 0; } QQmlObjectCreator::~QQmlObjectCreator() @@ -236,9 +236,9 @@ bool QQmlObjectCreator::populateDeferredProperties(QObject *instance) Q_ASSERT(!sharedState->allJavaScriptObjects); sharedState->allJavaScriptObjects = valueScope.alloc(compiledData->totalObjectCount); - QV4::Value *qmlBindingWrapper = valueScope.alloc(1); + QV4::QmlContext *qmlContext = static_cast<QV4::QmlContext *>(valueScope.alloc(1)); - qSwap(_qmlBindingWrapper, qmlBindingWrapper); + qSwap(_qmlContext, qmlContext); qSwap(_propertyCache, cache); qSwap(_qobject, instance); @@ -267,7 +267,7 @@ bool QQmlObjectCreator::populateDeferredProperties(QObject *instance) qSwap(_qobject, instance); qSwap(_propertyCache, cache); - qSwap(_qmlBindingWrapper, qmlBindingWrapper); + qSwap(_qmlContext, qmlContext); qSwap(_scopeObject, scopeObject); phase = ObjectsCreated; @@ -985,15 +985,16 @@ void QQmlObjectCreator::registerObjectWithContextById(int objectIndex, QObject * context->setIdProperty(idEntry.value(), instance); } -QV4::Heap::ExecutionContext *QQmlObjectCreator::currentQmlContext() +QV4::Heap::QmlContext *QQmlObjectCreator::currentQmlContext() { - if (!_qmlBindingWrapper->objectValue()) { + if (!_qmlContext->objectValue()) { QV4::Scope valueScope(v4); QV4::Scoped<QV4::QmlContextWrapper> qmlScope(valueScope, QV4::QmlContextWrapper::qmlScope(v4, context, _scopeObject)); QV4::ScopedContext global(valueScope, v4->rootContext()); - *_qmlBindingWrapper = v4->memoryManager->alloc<QV4::QmlBindingWrapper>(global, qmlScope); + _qmlContext->setM(global->newQmlContext(qmlScope)); + v4->popContext(); } - return static_cast<QV4::QmlBindingWrapper*>(_qmlBindingWrapper->objectValue())->context(); + return _qmlContext->d(); } QObject *QQmlObjectCreator::createInstance(int index, QObject *parent, bool isContextObject) @@ -1140,13 +1141,13 @@ QObject *QQmlObjectCreator::createInstance(int index, QObject *parent, bool isCo ++sharedState->allJavaScriptObjects; QV4::Scope valueScope(v4); - QV4::Value *qmlBindingWrapper = valueScope.alloc(1); + QV4::QmlContext *qmlContext = static_cast<QV4::QmlContext *>(valueScope.alloc(1)); - qSwap(_qmlBindingWrapper, qmlBindingWrapper); + qSwap(_qmlContext, qmlContext); bool result = populateInstance(index, instance, /*binding target*/instance, /*value type property*/0, bindingsToSkip); - qSwap(_qmlBindingWrapper, qmlBindingWrapper); + qSwap(_qmlContext, qmlContext); qSwap(_scopeObject, scopeObject); return result ? instance : 0; diff --git a/src/qml/qml/qqmlobjectcreator_p.h b/src/qml/qml/qqmlobjectcreator_p.h index c88c15b525..433bbf5bf2 100644 --- a/src/qml/qml/qqmlobjectcreator_p.h +++ b/src/qml/qml/qqmlobjectcreator_p.h @@ -107,7 +107,7 @@ private: void registerObjectWithContextById(int objectIndex, QObject *instance) const; - QV4::Heap::ExecutionContext *currentQmlContext(); + QV4::Heap::QmlContext *currentQmlContext(); enum Phase { Startup, @@ -143,7 +143,7 @@ private: QQmlRefPointer<QQmlPropertyCache> _propertyCache; QQmlVMEMetaObject *_vmeMetaObject; QQmlListProperty<void> _currentList; - QV4::Value *_qmlBindingWrapper; + QV4::QmlContext *_qmlContext; friend struct QQmlObjectCreatorRecursionWatcher; }; diff --git a/src/qml/qml/qqmltypeloader.cpp b/src/qml/qml/qqmltypeloader.cpp index 408f17ffde..eb65f732dd 100644 --- a/src/qml/qml/qqmltypeloader.cpp +++ b/src/qml/qml/qqmltypeloader.cpp @@ -647,6 +647,8 @@ void QQmlDataBlob::notifyComplete(QQmlDataBlob *blob) { Q_ASSERT(m_waitingFor.contains(blob)); Q_ASSERT(blob->status() == Error || blob->status() == Complete); + QQmlCompilingProfiler prof(QQmlEnginePrivate::get(typeLoader()->engine())->profiler, + blob->url()); m_inCallback = true; @@ -1194,6 +1196,8 @@ void QQmlTypeLoader::setData(QQmlDataBlob *blob, QQmlFile *file) void QQmlTypeLoader::setData(QQmlDataBlob *blob, const QQmlDataBlob::Data &d) { QML_MEMORY_SCOPE_URL(blob->url()); + QQmlCompilingProfiler prof(QQmlEnginePrivate::get(engine())->profiler, blob->url()); + blob->m_inCallback = true; blob->dataReceived(d); @@ -1212,6 +1216,8 @@ void QQmlTypeLoader::setData(QQmlDataBlob *blob, const QQmlDataBlob::Data &d) void QQmlTypeLoader::setCachedUnit(QQmlDataBlob *blob, const QQmlPrivate::CachedQmlUnit *unit) { QML_MEMORY_SCOPE_URL(blob->url()); + QQmlCompilingProfiler prof(QQmlEnginePrivate::get(engine())->profiler, blob->url()); + blob->m_inCallback = true; blob->initializeFromCachedUnit(unit); @@ -2253,8 +2259,6 @@ void QQmlTypeData::compile() m_compiledData = new QQmlCompiledData(typeLoader()->engine()); - QQmlCompilingProfiler prof(QQmlEnginePrivate::get(typeLoader()->engine())->profiler, finalUrlString()); - QQmlTypeCompiler compiler(QQmlEnginePrivate::get(typeLoader()->engine()), m_compiledData, this, m_document.data()); if (!compiler.compile()) { setError(compiler.compilationErrors()); diff --git a/src/qml/qml/qqmlxmlhttprequest.cpp b/src/qml/qml/qqmlxmlhttprequest.cpp index 0870e2b2c5..de7741675b 100644 --- a/src/qml/qml/qqmlxmlhttprequest.cpp +++ b/src/qml/qml/qqmlxmlhttprequest.cpp @@ -1358,7 +1358,11 @@ void QQmlXMLHttpRequest::error(QNetworkReply::NetworkError error) error == QNetworkReply::AuthenticationRequiredError || error == QNetworkReply::ContentReSendError || error == QNetworkReply::UnknownContentError || - error == QNetworkReply::ProtocolInvalidOperationError) { + error == QNetworkReply::ProtocolInvalidOperationError || + error == QNetworkReply::InternalServerError || + error == QNetworkReply::OperationNotImplementedError || + error == QNetworkReply::ServiceUnavailableError || + error == QNetworkReply::UnknownServerError) { m_state = Loading; dispatchCallback(); } else { diff --git a/src/quick/items/qquickitem.cpp b/src/quick/items/qquickitem.cpp index 0c9ee4fe73..80bad4dc27 100644 --- a/src/quick/items/qquickitem.cpp +++ b/src/quick/items/qquickitem.cpp @@ -2422,6 +2422,50 @@ bool QQuickItemPrivate::focusNextPrev(QQuickItem *item, bool forward) return true; } +QQuickItem *QQuickItemPrivate::nextTabChildItem(const QQuickItem *item, int start) +{ + if (!item) { + qWarning() << "QQuickItemPrivate::nextTabChildItem called with null item."; + return Q_NULLPTR; + } + const QList<QQuickItem *> &children = item->childItems(); + const int count = children.count(); + if (start < 0 || start >= count) { + qWarning() << "QQuickItemPrivate::nextTabChildItem: Start index value out of range for item" << item; + return Q_NULLPTR; + } + while (start < count) { + QQuickItem *child = children.at(start); + if (!child->d_func()->isTabFence) + return child; + ++start; + } + return Q_NULLPTR; +} + +QQuickItem *QQuickItemPrivate::prevTabChildItem(const QQuickItem *item, int start) +{ + if (!item) { + qWarning() << "QQuickItemPrivate::prevTabChildItem called with null item."; + return Q_NULLPTR; + } + const QList<QQuickItem *> &children = item->childItems(); + const int count = children.count(); + if (start == -1) + start = count - 1; + if (start < 0 || start >= count) { + qWarning() << "QQuickItemPrivate::prevTabChildItem: Start index value out of range for item" << item; + return Q_NULLPTR; + } + while (start >= 0) { + QQuickItem *child = children.at(start); + if (!child->d_func()->isTabFence) + return child; + --start; + } + return Q_NULLPTR; +} + QQuickItem* QQuickItemPrivate::nextPrevItemInTabFocusChain(QQuickItem *item, bool forward) { Q_ASSERT(item); @@ -2444,7 +2488,6 @@ QQuickItem* QQuickItemPrivate::nextPrevItemInTabFocusChain(QQuickItem *item, boo from = item->parentItem(); } bool skip = false; - const QQuickItem * const originalItem = item; QQuickItem * startItem = item; QQuickItem * firstFromItem = from; QQuickItem *current = item; @@ -2453,46 +2496,53 @@ QQuickItem* QQuickItemPrivate::nextPrevItemInTabFocusChain(QQuickItem *item, boo QQuickItem *last = current; bool hasChildren = !current->childItems().isEmpty() && current->isEnabled() && current->isVisible(); + QQuickItem *firstChild = Q_NULLPTR; + QQuickItem *lastChild = Q_NULLPTR; + if (hasChildren) { + firstChild = nextTabChildItem(current, 0); + if (!firstChild) + hasChildren = false; + else + lastChild = prevTabChildItem(current, -1); + } + bool isTabFence = current->d_func()->isTabFence; // coming from parent: check children if (hasChildren && from == current->parentItem()) { if (forward) { - current = current->childItems().first(); + current = firstChild; } else { - current = current->childItems().last(); + current = lastChild; if (!current->childItems().isEmpty()) skip = true; } - } else if (hasChildren && forward && from != current->childItems().last()) { + } else if (hasChildren && forward && from != lastChild) { // not last child going forwards int nextChild = current->childItems().indexOf(from) + 1; - current = current->childItems().at(nextChild); - } else if (hasChildren && !forward && from != current->childItems().first()) { + current = nextTabChildItem(current, nextChild); + } else if (hasChildren && !forward && from != firstChild) { // not first child going backwards int prevChild = current->childItems().indexOf(from) - 1; - current = current->childItems().at(prevChild); + current = prevTabChildItem(current, prevChild); if (!current->childItems().isEmpty()) skip = true; // back to the parent - } else if (current->parentItem()) { - current = current->parentItem(); + } else if (QQuickItem *parent = !isTabFence ? current->parentItem() : Q_NULLPTR) { // we would evaluate the parent twice, thus we skip if (forward) { skip = true; - } else if (!forward && !current->childItems().isEmpty()) { - if (last != current->childItems().first()) { - skip = true; - } else if (last == current->childItems().first()) { - if (current->isFocusScope() && current->activeFocusOnTab() && current->hasActiveFocus()) + } else if (QQuickItem *firstSibling = !forward ? nextTabChildItem(parent, 0) : Q_NULLPTR) { + if (last != firstSibling + || (parent->isFocusScope() && parent->activeFocusOnTab() && parent->hasActiveFocus())) skip = true; - } } + current = parent; } else if (hasChildren) { // Wrap around after checking all items forward if (forward) { - current = current->childItems().first(); + current = firstChild; } else { - current = current->childItems().last(); + current = lastChild; if (!current->childItems().isEmpty()) skip = true; } @@ -2500,9 +2550,9 @@ QQuickItem* QQuickItemPrivate::nextPrevItemInTabFocusChain(QQuickItem *item, boo from = last; if (current == startItem && from == firstFromItem) { // wrapped around, avoid endless loops - if (originalItem == contentItem) { + if (item == contentItem) { qCDebug(DBG_FOCUS) << "QQuickItemPrivate::nextPrevItemInTabFocusChain: looped, return contentItem"; - return item->window()->contentItem(); + return item; } else { qCDebug(DBG_FOCUS) << "QQuickItemPrivate::nextPrevItemInTabFocusChain: looped, return " << startItem; return startItem; @@ -3026,6 +3076,7 @@ QQuickItemPrivate::QQuickItemPrivate() , activeFocusOnTab(false) , implicitAntialiasing(false) , antialiasingValid(false) + , isTabFence(false) , dirtyAttributes(0) , nextDirtyItem(0) , prevDirtyItem(0) diff --git a/src/quick/items/qquickitem_p.h b/src/quick/items/qquickitem_p.h index 942b51bf68..6670975f20 100644 --- a/src/quick/items/qquickitem_p.h +++ b/src/quick/items/qquickitem_p.h @@ -427,6 +427,12 @@ public: bool activeFocusOnTab:1; bool implicitAntialiasing:1; bool antialiasingValid:1; + // isTabFence: When true, the item acts as a fence within the tab focus chain. + // This means that the item and its children will be skipped from the tab focus + // chain when navigating from its parent or any of its siblings. Similarly, + // when any of the item's descendants gets focus, the item constrains the tab + // focus chain and prevents tabbing outside. + bool isTabFence:1; enum DirtyType { TransformOrigin = 0x00000001, @@ -498,6 +504,8 @@ public: void itemToParentTransform(QTransform &) const; static bool focusNextPrev(QQuickItem *item, bool forward); + static QQuickItem *nextTabChildItem(const QQuickItem *item, int start); + static QQuickItem *prevTabChildItem(const QQuickItem *item, int start); static QQuickItem *nextPrevItemInTabFocusChain(QQuickItem *item, bool forward); static bool canAcceptTabFocus(QQuickItem *item); diff --git a/src/quick/util/qquickglobal.cpp b/src/quick/util/qquickglobal.cpp index 391e0b7347..25dd09c01f 100644 --- a/src/quick/util/qquickglobal.cpp +++ b/src/quick/util/qquickglobal.cpp @@ -374,7 +374,7 @@ public: return QMatrix4x4(matVals); } - const QMetaObject *getMetaObjectForMetaType(int type) + const QMetaObject *getMetaObjectForMetaType(int type) Q_DECL_OVERRIDE { switch (type) { case QMetaType::QColor: |