aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/plugins/qmltooling/qmldbg_profiler/qqmlprofileradapter.cpp2
-rw-r--r--src/plugins/qmltooling/qmldbg_server/qqmldebugserver.cpp1
-rw-r--r--src/qml/compiler/qqmltypecompiler.cpp40
-rw-r--r--src/qml/debugger/qqmlprofiler_p.h11
-rw-r--r--src/qml/jit/qv4isel_masm.cpp62
-rw-r--r--src/qml/jsruntime/qv4persistent.cpp63
-rw-r--r--src/qml/jsruntime/qv4persistent_p.h8
-rw-r--r--src/qml/jsruntime/qv4profiling.cpp29
-rw-r--r--src/qml/jsruntime/qv4profiling_p.h1
-rw-r--r--src/qml/jsruntime/qv4script.cpp16
-rw-r--r--src/qml/jsruntime/qv4script_p.h4
-rw-r--r--src/qml/qml/qqmlcontextwrapper.cpp13
-rw-r--r--src/qml/qml/qqmlobjectcreator.cpp23
-rw-r--r--src/qml/qml/qqmlobjectcreator_p.h4
-rw-r--r--src/qml/qml/qqmltypeloader.cpp8
-rw-r--r--src/qml/qml/qqmlxmlhttprequest.cpp6
-rw-r--r--src/quick/items/qquickitem.cpp89
-rw-r--r--src/quick/items/qquickitem_p.h8
-rw-r--r--src/quick/util/qquickglobal.cpp2
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: